简体   繁体   English

如何在 shell 函数中创建输出以使用 bat 进行单元测试?

[英]How to create output in a shell function for unit testing with bats?

After setting up a bats test framework that can test shell scripts in some directory, I am trying to expand the bats tests to test a shell function that is written in another shell file named passive_function.sh .在设置了可以在某个目录中测试 shell 脚本的 bats 测试框架后,我尝试扩展passive_function.sh测试以测试另一个 shell 文件中编写的 shell 函数。

Test setup测试设置

I created a template repository to perform shell testing.我创建了一个模板存储库来执行 shell 测试。 It contains a file called test_other_shell.bats in folder /test/ with content:它在文件夹/test/包含一个名为test_other_shell.bats的文件,内容为:

#!./test/libs/bats/bin/bats

load 'libs/bats-support/load'
load 'libs/bats-assert/load'

@test "running the file in /src/active_function.sh." {
    run ./src/active_function.sh 9 33
    assert_output 42
}

And I created a file called main.sh with content:我创建了一个名为main.sh的文件,内容如下:

#!/bin/sh
some_active_function() {
    sum="$1 + $2" | bc -l
    echo "$sum"
}

some_active_function

Test result测试结果

Running the bats test from terminal fails with output:从终端运行 bats 测试失败并输出:

 ✗ running the file in /src/active_function.sh.
   (from function `assert_output' in file test/libs/bats-assert/src/assert.bash, line 239,
    in test file test/test_active_function.bats, line 8)
     `assert_output 42' failed
   
   -- output differs --
   expected : 42
   actual   : 
   --

Function verification功能验证

I manually verified this function returns 42 by running:我通过运行手动验证此函数返回42

source ./src/active_function.sh; some_active_function 9 33

from terminal, which prints:从终端,打印:

42
42

Question

How can I write a bats test that tests a shell function which returns the addition of input 2 integer numbers?如何编写一个 bats 测试来测试一个 shell 函数,该函数返回输入 2 个整数的加法?

Eg if I call somefunc 3 5 the test pass if the function returns 8 , and fail otherwise.例如,如果我调用somefunc 3 5测试通过,如果函数返回8 ,否则失败。

sum="$1 + $2" | bc -l

does not set the sum variable to the sum of the numbers:设置sum变量的数字的总和:

  • the pipe means that bash runs each command in the pipeline in a separate subshell.管道意味着 bash 在单独的子 shell 中运行管道中的每个命令。
  • the first subshell gets sum assigned the string "9 + 33", and there's no output第一个子shell获得sum分配字符串“9 + 33”,并且没有输出
  • the second subshell starts bc with an empty string sent to it's stdin, so bc outputs nothing第二个子shell以一个空字符串开始 bc 发送到它的标准输入,所以 bc 什么都不输出
  • the sum variable in the function's scope remains uninitialized.函数作用域中的sum变量保持未初始化状态。

Next, when you execute that code, you define the function and then invoke it with no parameters.接下来,当您执行该代码时,您定义该函数,然后不带参数调用它。 You need the last line to be你需要最后一行

some_active_functionm "$@"

Also, if you want to test the function you don't really need to run a script:此外,如果您想测试该功能,您实际上并不需要运行脚本:

@test "running the file in /src/active_function.sh." {
    source ./src/active_function.sh
    output=$(some_active_function 9 33)
    ((output == 42))
}

Untested.未经测试。 You could probably get away with你可能会逃脱

load ./src/active_function.sh

@test "running the file in /src/active_function.sh." {
    output=$(some_active_function 9 33)
    ((output == 42))
}

As indicated in the answer by glenn jackman, I did not pass the incoming arguments to the function in the last line of the function.正如 glenn jackman 的回答所示,我没有在函数的最后一行将传入参数传递给函数。 Furthermore, my summation method was incorrect.此外,我的求和方法不正确。 A solution (and non-arithmatic example) is included below.下面包含一个解决方案(和非算术示例)。

Test and function: adding two numbers测试与功能:两个数相加

A shell script with a function that adds two numbers named active_function_addition.sh with content:带有一个函数的 shell 脚本,该函数将两个名为active_function_addition.sh数字与内容相加:

#!/bin/sh
some_active_function() {
    sum=$(expr "$1" + "$2")
    echo $sum
}
some_active_function "$@"

And a unit test in the form of a bats file, with name test_active_function_addition.bats and content:而在一个形式的单元测试bats文件,名称为test_active_function_addition.bats和内容:

#!./test/libs/bats/bin/bats

load 'libs/bats-support/load'
load 'libs/bats-assert/load'

@test "running the file in /src/active_function_addition.sh." {
    run ./src/active_function_addition.sh 9 33
    assert_output 42
}

Test and function: string manipulation测试与功能:字符串操作

A shell script with a function that changes upper case characters to lower case characters named active_function_string_manipulation.sh with content:带有将大写字符更改为小写字符的函数的 shell 脚本,名为active_function_string_manipulation.sh ,其内容为:

##################################################################
# Purpose: Converts a string to lower case
# Arguments:
#   $@ -> String to convert to lower case
##################################################################
function to_lower() 
{
    local str="$@"
    local output
    output=$(tr '[A-Z]' '[a-z]'<<<"${str}")
    echo $output
}
to_lower "$@"

And a unit test in the form of a bats file, with name test_active_function_addition.bats and content:而在一个形式的单元测试bats文件,名称为test_active_function_addition.bats和内容:

#!./test/libs/bats/bin/bats

load 'libs/bats-support/load'
load 'libs/bats-assert/load'

@test "running the file in /src/active_function_string_manipulation.sh." {
    input="This Is a TEST"
    run ./src/active_function_string_manipulation.sh "This Is a TEST"
    assert_output "this is a test"
}

Test results检测结果

Both tests pass.两项测试均通过。

Notes笔记

  1. During the debugging and testing I determined I missed more relevant knowledge.在调试和测试期间,我确定我错过了更多相关知识。 When I ran the source ./src/active_function.sh; some_active_function 9 33当我运行source ./src/active_function.sh; some_active_function 9 33 source ./src/active_function.sh; some_active_function 9 33 I retrieved output 42 twice, at some point in time. source ./src/active_function.sh; some_active_function 9 33我在某个时间点检索了输出42两次。 However, since I did not actually passed the input arguments to the function, the actual return would be void in a clean setting (eg the unit test).但是,由于我实际上并没有将输入参数传递给函数,因此在干净的设置(例如单元测试)中实际返回将是无效的。 When I closed the terminal and re-opened the terminal I did indeed receive the void return on the manual test line.当我关闭终端并重新打开终端时,我确实收到了手动测试线上的无效返回。 I think that during the manual tries of different summing methods that some variables were stored in memory without me being aware of that which resulted in the 42 being displayed without the arguments being passed.我认为在手动尝试不同的求和方法期间,某些变量存储在内存中,而我没有意识到导致 42 显示而没有传递参数的原因。 I did not reproduce this behaviour in a controlled manner.我没有以受控的方式重现这种行为。

  2. This solution requires the entire shell script to be run, which might take a lot of time.此解决方案需要运行整个 shell 脚本,这可能需要很多时间。 Glenn jackman gave an answer with a more elegant and more efficient solution that only runs a specific function without having to run a complete script. Glenn jackman 给出了一个更优雅、更高效的解决方案,它只运行特定的功能,而不必运行完整的脚本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM