单元测试bash脚本
-
20-09-2019 - |
题
我们有一个系统,有一些bash脚本运行的一Java代码。由于我们正在努力测试的一切可能打破,以及这些bash脚本可以打破,我们需要测试它们。
问题是它是难以测试砸向脚本。
有没有一种方法或最佳做法,以测试bash脚本?或者我们应该放弃使用bash脚本和寻找替代解决方案的可测试?
解决方案 2
我从讨论组以下答案:
有可能导入(包括 无论)的程序(功能, 不管它的名字命名)来自外部 文件。这是关键,以书面形式 测试脚本:你打破了你 脚本到独立程序 然后可以导入到两个 您的行书和您的测试 脚本,然后你有你的跑步 脚本是尽可能简单。
此方法是像依赖注入脚本,和声音合理。避免的bash脚本和使用更多的可测试和更少的模糊的语言是优选的。
其他提示
实际上有一个 舒尼特2, ,一个基于 xUnit 的单元测试框架,用于基于 Bourne 的 shell 脚本。我自己没有使用过它,但可能值得一试。
之前也有人问过类似的问题:
你为什么说这是“硬”来测试的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
}
我很喜欢 shell2junit 时,一个实用程序来生成从bash脚本测试的JUnit状输出。因为所生成的报告然后可以通过持续集成系统,如JUnit的插件詹金斯和竹读取这是有用的。
虽然shell2junit不提供全面击脚本框架如 shunit2 时,它允许你的测试结果不错报告。
尝试 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环境进行测试。
提供一个尝试 assert.sh
source "./assert.sh"
local expected actual
expected="Hello"
actual="World!"
assert_eq "$expected" "$actual" "not equivalent!"
# => x Hello == World :: not equivalent!
希望它能帮助!
我不能相信没有人谈论 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,因为它是一个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
及其底片,和脚本断言使用这个库两者的测试功能。对我来说,此框架提供了最增益为至少开销。
我创建 外壳规范 因为我想要一个易于使用且有用的工具。
它由纯 POSIX shell 脚本编写。它已经与 Shuunit2 以外的许多 shell 进行了测试。它具有比bats/bats-core更强大的功能。
例如,支持嵌套块、易于模拟/存根、易于跳过/挂起、参数化测试、断言行号、按行号执行、并行执行、随机执行、TAP/JUnit 格式化程序、覆盖率和 CI 集成、分析器等。
请参阅项目页面上的演示。
我已经尝试了很多这里提出的解决方案,但发现他们大多笨重又难用,所以我建立我自己的小测试框架:的 https://github.com/meonlol/t-bash
这是在回购只是一个文件,你可以简单地直接运行,有一组基本的JUnit的风格断言。
我的专业用它在几个内部项目,并能够让我们的bash脚本超稳定抗回归
您可能想看看bash_unit:
我发现很难证明在较大的脚本中使用 bash 是合理的 Python 具有如此巨大的优势:
- Try/Except 允许编写更强大的脚本,并且能够在发生错误时撤消更改。
- 您不必使用晦涩的语法,例如 '
if [ x"$foo" = x"$bar"]; then ...
' 这很容易出错。 - 使用以下命令轻松解析选项和参数
getopt
模块(还有一个更简单的用于解析参数的模块,但我忘记了这个名字)。 - Python 允许您使用列表/字典和对象,而不是基本的字符串和数组。
- 访问适当的语言工具,例如正则表达式、数据库(确保您可以将所有内容通过管道传输到
mysql
bash 中的命令,但这不是编写代码的最好方法)。 - 无需担心使用正确的形式
$*
或者"$*"
或者"$@"
或者$1
或者"$1"
, ,文件名中的空格不是问题,等等,等等。
现在我只使用 bash 来执行最简单的脚本。