我们有一个系统,有一些bash脚本运行的一Java代码。由于我们正在努力测试的一切可能打破,以及这些bash脚本可以打破,我们需要测试它们。

问题是它是难以测试砸向脚本。

有没有一种方法或最佳做法,以测试bash脚本?或者我们应该放弃使用bash脚本和寻找替代解决方案的可测试?

有帮助吗?

解决方案 2

我从讨论组以下答案:

  

有可能导入(包括   无论)的程序(功能,   不管它的名字命名)来自外部   文件。这是关键,以书面形式   测试脚本:你打破了你   脚本到独立程序   然后可以导入到两个   您的行书和您的测试   脚本,然后你有你的跑步   脚本是尽可能简单。

此方法是像依赖注入脚本,和声音合理。避免的bash脚本和使用更多的可测试和更少的模糊的语言是优选的。

其他提示

实际上有一个 舒尼特2, ,一个基于 xUnit 的单元测试框架,用于基于 Bourne 的 shell 脚本。我自己没有使用过它,但可能值得一试。

之前也有人问过类似的问题:

水龙头-符合Bash测试: 砸自动测试系统

点击,试验任何协议,是一个简单的基于文本之间的接口的测试模块在一个试验束。水龙头开始生活的一部分测试束Perl但现在已经实现,在C、C++、Python,PHP,Perl、Java,JavaScript,和其他人。

环氧树脂 是砸测试框架内的我设计主要是为了测试其他的软件,但我用它来测试模块砸以及包括 本身纸箱.

主要优点是比较低的编码的开销,不限断言筑巢和灵活选择的说法进行验证。

我做了一个 演示 它比较 BeakerLib -一个框架,用于通过一些在红色的帽子。

尼基塔*索博列夫写了一个出色的博客比较的几个不同的庆典的测试框架: 测试应用Bash

不耐烦:尼基塔的结论是使用 蝙蝠 但是尼基塔错过了 蝙蝠核 项目似乎对我来说是一个使用前为原来的蝙蝠项目没有直积极保持自2013年。

你为什么说这是“硬”来测试的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:

https://github.com/pgrange/bash_unit

我发现很难证明在较大的脚本中使用 bash 是合理的 Python 具有如此巨大的优势:

  • Try/Except 允许编写更强大的脚本,并且能够在发生错误时撤消更改。
  • 您不必使用晦涩的语法,例如 'if [ x"$foo" = x"$bar"]; then ...' 这很容易出错。
  • 使用以下命令轻松解析选项和参数 getopt 模块(还有一个更简单的用于解析参数的模块,但我忘记了这个名字)。
  • Python 允许您使用列表/字典和对象,而不是基本的字符串和数组。
  • 访问适当的语言工具,例如正则表达式、数据库(确保您可以将所有内容通过管道传输到 mysql bash 中的命令,但这不是编写代码的最好方法)。
  • 无需担心使用正确的形式 $* 或者 "$*" 或者 "$@" 或者 $1 或者 "$1", ,文件名中的空格不是问题,等等,等等。

现在我只使用 bash 来执行最简单的脚本。

scroll top