Answers:
实际上,有一个shunit2,这是一个基于xUnit的单元测试框架,用于基于Bourne的shell脚本。我自己没有使用过,但是可能值得一试。
之前曾问过类似的问题:
我从一个讨论组得到以下答案:
可以从外部文件导入(包括任何内容)过程(函数,无论其名称如何)。这就是编写测试脚本的关键:将脚本分解成独立的过程,然后将其导入运行脚本和测试脚本中,然后使运行脚本尽可能简单。
此方法类似于脚本的依赖注入,听起来很合理。最好避免使用bash脚本,而使用更具可测试性和不太模糊的语言。
TAP兼容的Bash测试:Bash自动化测试系统
TAP(任何测试协议)是测试工具中测试模块之间基于文本的简单接口。TAP最初是Perl测试工具的一部分,但现在具有C,C ++,Python,PHP,Perl,Java,JavaScript等实现。
Nikita Sobolev写了一篇很棒的博客文章,比较了几种不同的bash测试框架:测试Bash应用程序
对于不耐烦的人:Nikita的结论是使用Bats,但是Nikita似乎错过了Bats-core项目,在我看来这是一个可以继续使用的项目,因为自2013年以来一直没有积极维护原始的Bats项目。
为什么说测试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
}
我创建shellspec是因为我想要一个易于使用且有用的工具。
它由纯POSIX shell脚本编写。它比shunit2对许多外壳进行了更多测试。它具有比bats / bats-core强大的功能。
例如,支持嵌套块,易于模拟/存根,易于跳过/挂起,参数化测试,断言行号,按行号执行,并行执行,随机执行,TAP / JUnit格式化程序,覆盖率和CI集成,探查器等。
请参阅项目页面上的演示。
我非常喜欢shell2junit,该实用程序可从Bash脚本测试生成类似JUnit的输出。这很有用,因为生成的报告随后可以被持续集成系统(例如Jenkins和Bamboo的JUnit插件)读取。
尽管shell2junit没有提供像shunit2这样的全面的Bash脚本框架,但它确实允许您很好地报告测试结果。
尝试bashtest。这是测试脚本的简单方法。例如,您do-some-work.sh
更改了一些配置文件。例如,将新行添加PASSWORD = 'XXXXX'
到配置文件/etc/my.cfg
。
您逐行编写bash命令,然后检查输出。
安装:
pip3 install bashtest
创建测试只是编写bash命令。
档案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
也许可以使用或有助于
https://thorsteinssonh.github.io/bash_test_tools/
打算用TAP协议编写结果,我认为这对CI很有用,对于希望使用shell环境的人也很有用。我想有些事情在外壳环境中运行,因此,有些人可能认为应该在其外壳环境中进行测试。
我不敢相信没有人谈论OSHT!它与TAP和JUnit 都兼容,它是纯外壳程序(也就是说,不涉及其他任何语言),它也可以独立工作,并且简单直接。
测试如下所示(摘录自项目页面的片段):
#!/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
最后一个测试显示为“不正常”,但退出代码为0,因为它是a 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
。对我而言,此框架以最少的开销提供了最大的收益。
我已经尝试了这里介绍的许多解决方案,但是发现其中大多数解决方案体积庞大且难以使用,因此我建立了自己的小型测试框架:https : //github.com/meonlol/t-bash
这只是回购中的一个文件,您可以直接运行,并具有一组基本的JUnit样式断言。
我已经在几个内部项目中专业地使用过它,并且能够使我们的bash脚本具有超强的稳定性和抗回归性。
您可能要看一下bash_unit:
看一下Outthentic,它很简单,可以通过多种语言(可选 Perl,Python,Ruby,Bash)和跨平台(Linux,Windows)框架进行扩展,以测试任何命令行应用程序。
当Python具有如此巨大的优势时,我发现很难为大型脚本使用bash :
if [ x"$foo" = x"$bar"]; then ...
容易 '。getopt
模块可以(还有一个用于解析参数的更简单的模块,但是名称使我无所适从)。mysql
bash传递到命令中,但这不是编写代码的最佳方法)。$*
or或"$*"
or "$@"
或$1
or 的正确格式,"$1"
文件名中的空格不是问题,等等,等等,等等。现在,我仅将bash用于最简单的脚本。
if [[ $foo = $bar ]]; then ...
。这仍然不比python所提供的要好,但是比您介绍的要好。
trap
(在发生错误时进行清除/撤消)以及正则表达式(即[[ $1 =~ ^[1-3]{3}$ ]]
)。我很确定您使用的晦涩语法是参考而test
不是bash的旧实现。Bash非常适合与现有的命令行工具进行交互...通常,使用单个管道连接Python awk
或grep
比使用Python替代要容易得多。
optparse
其继任者argparse
。我从未见过有人使用该getopt
模块,也从未亲自使用过该模块。该getopt
实用程序是伟大的。一旦有了良好的模式,从shell解析参数根本就不是问题。除非您尝试实现git-style子命令之类的东西,否则没有什么麻烦。