多年来我所使用的每一件产品都涉及到某种程度的shell脚本(或Windows上的批处理文件,PowerShell等)。尽管我们用Java或C ++编写了大量代码,但似乎总有一些集成或安装任务最好用shell脚本完成。
shell脚本因此成为已发布代码的一部分,因此需要像编译代码一样进行测试。有没有人有使用某些shell脚本单元测试框架的经验,例如shunit2?我现在主要对Linux shell脚本感兴趣;我想知道测试工具如何复制其他xUnit框架的功能和易用性,以及与CruiseControl或Hudson等连续构建系统集成是多么容易。
答案 0 :(得分:47)
更新2019-03-01:我现在的偏好是bats。我在小项目上使用了几年。我喜欢简洁明了的语法。我没有将它与CI / CD框架集成,但它的退出状态确实反映了套件的整体成功/失败,这比shunit2更好,如下所述。
以前的答案:
我正在将shunit2用于与Linux环境中的Java / Ruby Web应用程序相关的shell脚本。它易于使用,与其他xUnit框架没有很大的不同。
我没有尝试与CruiseControl或Hudson / Jenkins集成,但是通过其他方式实现持续集成我遇到了这些问题:
答案 1 :(得分:26)
想知道为什么没有人提到BATS。它是最新的,TAP - 符合。
说明:
#!/usr/bin/env bats
@test "addition using bc" {
result="$(echo 2+2 | bc)"
[ "$result" -eq 4 ]
}
执行命令
$ bats addition.bats
✓ addition using bc
1 tests, 0 failures
答案 2 :(得分:20)
@ blake-mizerany的综述听起来很棒,我将来应该使用它,但这是我用于创建单元测试的“穷人”方法:
functions.sh
和source
放入脚本中。您可以使用source `dirname $0`/functions.sh
来实现此目的。在functions.sh
结尾处,将您的测试用例嵌入以下if条件中:
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
fi
您的测试是对函数的文字调用,然后是对退出代码和变量值的简单检查。我想添加一个简单的实用函数,如下所示,以便于编写:
function assertEquals()
{
msg=$1; shift
expected=$1; shift
actual=$1; shift
if [ "$expected" != "$actual" ]; then
echo "$msg EXPECTED=$expected ACTUAL=$actual"
exit 2
fi
}
最后,直接运行functions.sh
以执行测试。
以下是展示方法的示例:
#!/bin/bash
function adder()
{
return $(($1+$2))
}
(
[[ "${BASH_SOURCE[0]}" == "${0}" ]] || exit 0
function assertEquals()
{
msg=$1; shift
expected=$1; shift
actual=$1; shift
/bin/echo -n "$msg: "
if [ "$expected" != "$actual" ]; then
echo "FAILED: EXPECTED=$expected ACTUAL=$actual"
else
echo PASSED
fi
}
adder 2 3
assertEquals "adding two numbers" 5 $?
)
答案 3 :(得分:17)
综述: http://bmizerany.github.com/roundup/
README中有一篇文章的链接详细解释了它。
答案 4 :(得分:8)
除roundup和shunit2外,我对shell单元测试工具的概述还包括assert.sh和shelltestrunner。
我大多同意综合作者对shunit2的批评(其中一些是主观的),所以在查看文档和示例后我排除了shunit2。虽然看起来很熟悉有一些jUnit的经验。
在我看来,shelltestrunner是我看过的最原始的工具,因为它使用简单的声明性语法进行测试用例定义。像往常一样,任何抽象级别都会以一些灵活性为代价提供一些便利。尽管简单性很有吸引力,但我发现该工具对我的情况也有限制,主要是因为缺乏定义setup / tearDown操作的方法(例如,在测试之前操作输入文件,在测试后删除状态文件)等等。)。
我起初有点困惑,assert.sh只允许断言输出或退出状态,而我需要两者。足够长,可以使用综合编写几个测试用例。但是我很快发现综合的set -e
模式不方便,因为在某些情况下,除了stdout之外,预期非零退出状态作为传达结果的一种方式,这使得测试用例在所述模式中失败。 One of the samples显示了解决方案:
status=$(set +e ; rup roundup-5 >/dev/null ; echo $?)
但是如果我需要非零退出状态和输出呢?当然,我可以在调用之前set +e
,在整个测试用例之后set -e
之后或set +e
。但这违反了综述的原则"Everything is an Assertion"。所以我觉得我开始反对这个工具了。
到那时我已经意识到assert.sh允许仅断言退出状态或输出的“缺点”实际上是一个非问题,因为我可以使用像这样的复合表达式传入test
/ p>
output=$($tested_script_with_args)
status=$?
expected_output="the expectation"
assert_raises "test \"$output\" = \"$expected_output\" -a $status -eq 2"
由于我的需求非常基本(运行一套测试,显示一切正常或失败),我喜欢assert.sh的简单性,所以这就是我选择的。
答案 5 :(得分:2)
在寻找一个简单的shell单元测试框架后,可以为Jenkins生成xml结果而不是真正找到任何东西,我写了一个。
它在sourceforge上 - 项目的名称是jshu。
答案 6 :(得分:2)
你应该尝试assert.sh lib,非常方便,易于使用
local expected actual
expected="Hello"
actual="World!"
assert_eq "$expected" "$actual" "not equivalent!"
# => x Hello == World :: not equivalent!
答案 7 :(得分:1)
我最近发布了一个名为shellspec的新测试框架。
shellspec是BDD样式测试框架。 它适用于POSIX兼容的shell脚本,包括bash,破折号,ksh,busybox等。
当然,退出状态反映了规范运行的结果 并且具有符合TAP的格式化程序。
specfile接近自然语言,易于阅读, 也是与Shell脚本兼容的语法。
#shellcheck shell=sh
Describe 'sample'
Describe 'calc()'
calc() { echo "$(($*))"; }
It 'calculates the formula'
When call calc 1 + 2
The output should equal 3
End
End
End