我们有一个系统,除了Java代码外还有一些Bash脚本在运行。由于我们试图测试可能会出问题的所有内容,而这些Bash脚本可能会出问题,因此我们想要对它们进行测试。
问题是很难测试Bash脚本。
是否有一种方法或最佳实践来测试Bash脚本?还是应该放弃使用Bash脚本并寻找可测试的替代方案?
我们有一个系统,除了Java代码外还有一些Bash脚本在运行。由于我们试图测试可能会出问题的所有内容,而这些Bash脚本可能会出问题,因此我们想要对它们进行测试。
问题是很难测试Bash脚本。
是否有一种方法或最佳实践来测试Bash脚本?还是应该放弃使用Bash脚本并寻找可测试的替代方案?
其实有一个基于xUnit的单元测试框架,叫做shunit2,适用于 Bourne shell 脚本。我自己没有使用过,但值得一试。
类似的问题以前已经被提出:
TAP 兼容的Bash测试: Bash自动化测试系统
TAP,即测试任意协议,是测试工具中的测试模块之间的一种简单文本接口。TAP最初是Perl测试工具中的一部分,但现在还有C、C++、Python、PHP、Perl、Java、JavaScript等的实现。
可以从外部文件中导入(包含、引入)一个过程(函数或其他名称)。这是编写测试脚本的关键:将脚本分解为独立的过程,然后可以将其导入到运行脚本和测试脚本中。这样,你的运行脚本就尽可能简单了。
这种方法类似于脚本的依赖注入,听起来很合理。避免使用Bash脚本并使用更易测试和不那么晦涩的语言是更可取的。#!/bin/bash
. osht.sh
# Optionally, indicate number of tests to safeguard against abnormal exits
PLAN 13
# Comparing stuff
IS $(whoami) != root
var="foobar"
IS "$var" =~ foo
ISNT "$var" == foo
# test(1)-based tests
OK -f /etc/passwd
NOK -w /etc/passwd
# Running stuff
# Check exit code
RUNS true
NRUNS false
# Check stdio/stdout/stderr
RUNS echo -e 'foo\nbar\nbaz'
GREP bar
OGREP bar
NEGREP . # verify empty
# diff output
DIFF <<EOF
foo
bar
baz
EOF
# TODO and SKIP
TODO RUNS false
SKIP test $(uname -s) == Darwin
$ bash test.sh
1..13
ok 1 - IS $(whoami) != root
ok 2 - IS "$var" =~ foo
ok 3 - ISNT "$var" == foo
ok 4 - OK -f /etc/passwd
ok 5 - NOK -w /etc/passwd
ok 6 - RUNS true
ok 7 - NRUNS false
ok 8 - RUNS echo -e 'foo\nbar\nbaz'
ok 9 - GREP bar
ok 10 - OGREP bar
ok 11 - NEGREP . # verify empty
ok 12 - DIFF <<EOF
not ok 13 - TODO RUNS false # TODO Test Know to fail
TODO
。也可以设置详细模式:$ OSHT_VERBOSE=1 bash test.sh # Or -v
1..13
# dcsobral \!= root
ok 1 - IS $(whoami) != root
# foobar =\~ foo
ok 2 - IS "$var" =~ foo
# \! foobar == foo
ok 3 - ISNT "$var" == foo
# test -f /etc/passwd
ok 4 - OK -f /etc/passwd
# test \! -w /etc/passwd
ok 5 - NOK -w /etc/passwd
# RUNNING: true
# STATUS: 0
# STDIO <<EOM
# EOM
ok 6 - RUNS true
# RUNNING: false
# STATUS: 1
# STDIO <<EOM
# EOM
ok 7 - NRUNS false
# RUNNING: echo -e foo\\nbar\\nbaz
# STATUS: 0
# STDIO <<EOM
# foo
# bar
# baz
# EOM
ok 8 - RUNS echo -e 'foo\nbar\nbaz'
# grep -q bar
ok 9 - GREP bar
# grep -q bar
ok 10 - OGREP bar
# \! grep -q .
ok 11 - NEGREP . # verify empty
ok 12 - DIFF <<EOF
# RUNNING: false
# STATUS: 1
# STDIO <<EOM
# EOM
not ok 13 - TODO RUNS false # TODO Test Know to fail
.t
扩展名并将其放置在 t
子目录中,您可以使用 prove(1)
(Perl 的一部分)来运行它:$ prove
t/test.t .. ok
All tests successful.
Files=1, Tests=13, 0 wallclock secs ( 0.03 usr 0.01 sys + 0.11 cusr 0.16 csys = 0.31 CPU)
Result: PASS
设置OSHT_JUNIT
或传递-j
以生成JUnit输出。JUnit也可以与prove(1)
结合使用。
我使用这个库来测试函数,通过引用它们的文件并使用IS
/OK
及其否定运行断言,以及使用RUN
/NRUN
来运行脚本。对我来说,这个框架提供了最少的开销,却获得了最大的收益。
你为什么说测试Bash脚本很“难”?
下面这样的测试包装器有什么问题吗?
#!/bin/bash
set -e
errors=0
results=$($script_under_test $args<<ENDTSTDATA
# inputs
# go
# here
#
ENDTSTDATA
)
[ "$?" -ne 0 ] || {
echo "Test returned error code $?" 2>&1
let errors+=1
}
echo "$results" | grep -q $expected1 || {
echo "Test Failed. Expected $expected1"
let errors+=1
}
# And so on, et cetera, ad infinitum, ad nauseum
[ "$errors" -gt 0 ] && {
echo "There were $errors errors found"
exit 1
}
试试使用assert.sh:
source "./assert.sh"
local expected actual
expected="Hello"
actual="World!"
assert_eq "$expected" "$actual" "not equivalent!"
# => x Hello == World :: not equivalent!
尝试使用bashtest。这是测试脚本的简单方法。例如,您有一个名为do-some-work.sh
的脚本,它会更改一些配置文件。例如,在配置文件/etc/my.cfg
中添加一行新的PASSWORD = 'XXXXX'
。
您可以逐行编写Bash命令,然后检查输出。
安装:
pip3 install bashtest
test-do-some-work.bashtest
:# Run the script
$ ./do-some-work.sh > /dev/null
# Testing that the line "PASSWORD = 'XXXXX'" is in the file /etc/my.cfg
$ grep -Fxq "PASSWORD = 'XXXXX'" /etc/my.cfg && echo "YES"
YES
bashtest *.bashtest