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

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

在设置了可以测试某个目录中的 shell 脚本的 bats 测试框架之后,我试图扩展 bats 测试以测试另一个 [=51] 中编写的 shell 函数=] 文件名为 passive_function.sh.

测试设置

我创建了一个 template repository 来执行 shell 测试。它在文件夹 /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
}

然后我创建了一个名为 main.sh 的文件,内容为:

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

some_active_function

测试结果

运行 来自终端的蝙蝠测试失败并输出:

 ✗ 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   : 
   --

功能验证

我通过运行手动验证了这个函数returns 42:

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

来自终端,打印:

42
42

问题

如何编写蝙蝠测试来测试 shell 函数,其中 returns 输入 2 个整数相加?

例如如果我调用 somefunc 3 5 如果函数 returns 8 测试通过,否则失败。

sum=" + " | bc -l

是否sum变量设置为数字的总和:

  • 管道意味着 bash 运行 在单独的子 shell 中管道中的每个命令。
  • 第一个子 shell sum 分配了字符串“9 + 33”,并且没有输出
  • 第二个子 shell 开始 bc 并向其标准输入发送一个空字符串,因此 bc 不输出任何内容
  • 函数的作用域中的sum变量保持未初始化状态。

接下来,当您执行该代码时,您定义函数,然后不带参数调用它。你需要最后一行是

some_active_functionm "$@"

此外,如果您想测试 函数 ,您实际上 不需要 到 运行 脚本:

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

未经测试。你可能会逃脱

load ./src/active_function.sh

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

正如 glenn jackman 的回答中所指出的,我没有在函数的最后一行将传入参数传递给函数。此外,我的求和方法不正确。下面包含一个解决方案(和 non-arithmatic 示例)。

测试和功能:将两个数字相加

一个 shell 脚本,其功能是将两个名为 active_function_addition.sh 的数字相加,内容为:

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

以及 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
}

测试和功能:字符串操作

一个 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 "$@"

以及 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"
}

测试结果

两个测试都通过了。

备注

  1. 在调试和测试的过程中我确定我漏掉了更多的相关知识。当我 运行 source ./src/active_function.sh; some_active_function 9 33 时,我在某个时间点检索了输出 42 两次。但是,由于我实际上并没有将输入参数传递给函数,因此实际的 return 在干净的设置(例如单元测试)中将无效。当我关闭终端和 re-opened 终端时,我确实在手动测试线上收到了 void return 。我认为在手动尝试不同的求和方法期间,一些变量存储在内存中而我没有意识到这导致 42 在没有传递参数的情况下显示。我没有以受控方式重现此行为。

  2. 此解决方案要求整个 shell 脚本为 运行,这可能会花费很多时间。 Glenn jackman 给出了一个更优雅和更有效的解决方案的答案,该解决方案仅 运行 一个特定的功能而无需 运行 一个完整的脚本。