我正在制作一个外壳脚本,该外壳脚本作为CI管道的一部分运行一堆测试。我想运行所有测试(如果一项测试失败,我不想早日退出)。然后,在脚本末尾,如果任何测试失败,我想返回一个负的退出代码。
任何帮助将不胜感激。我觉得这将是一个非常常见的用例,但是我无法通过大量研究找到解决方案。我很确定我不想要set -e
,因为这早就退出了。
我当前的想法是创建一个标记以跟踪任何失败的测试:
flag=0
pytest -s || flag=1
go test -v ./... || flag=1
exit $flag
这似乎很奇怪,并且比需要的工作还多,但是我对bash脚本还是陌生的。我想念什么吗?
答案 0 :(得分:4)
一种可能的方法是通过trap
和ERR
捕获非零退出代码。假设您的测试不包含流水线|
,而只是将错误代码直接返回到启动的shell,您可以这样做
#!/usr/bin/env bash
exitCodeArray=()
onFailure() {
exitCodeArray+=( "$?" )
}
trap onFailure ERR
# Add all your tests here
addNumbers () {
local IFS='+'
printf "%s" "$(( $* ))"
}
在以上代码段之后的任意位置添加测试。因此,只要测试返回非零返回码,我们就将退出码添加到数组中。因此,对于最后的断言,我们检查数组元素的总和是否为0
,因为在理想情况下,所有情况都应在成功的情况下返回。我们重置
trap
集
trap '' ERR
if (( $(addNumbers "${exitCodeArray[@]}") )); then
printf 'some of your tests failed\n' >&2
exit -1
fi
答案 1 :(得分:1)
我可以想象使用 less 代码的唯一方法是,如果外壳具有某种特殊的all
复合命令,看起来像
# hypothetical all command
all do
pytest -s
go test -v ./...
done
其退出状态是所包含命令的退出状态的逻辑or
。 (类似的any
命令会将其命令退出状态的逻辑and
作为其自己的退出状态。)
缺少这样的命令,您当前使用的方法就是我要使用的方法。您可以修改@melpomene对chk
函数的建议(我会在命令后叫 ,而不是让它调用您的命令以便它可以与任意shell命令一起工作):
chk () { flag=$(( flag | $? )); }
flag=0
pytest -s; chk
go test -v ./...; chk
exit "$flag"
如果您不将其用于其他用途,则可以滥用DEBUG
陷阱来在每个命令之前更新flag
。
trap 'flag=$((flag | $?))' DEBUG
pytest -s
go test -v ./...
exit "$flag"
(请注意,调试陷阱在 之前执行,而Shell在执行命令之前而不是 之后立即执行另一个命令。唯一重要的是您希望陷阱在最后一个命令完成和外壳退出之间触发,但是仍然值得注意。)
答案 2 :(得分:1)
我投票支持Inian的回答。陷阱似乎是完美的选择。
也就是说,您还可以通过使用数组简化事情。
#!/usr/bin/env bash
testlist=(
"pytest -s"
"go test -v ./..."
)
for this in "${testlist[@]}"; do
$this || flag=1
done
exit $flag
当然,如果您要制作更通用的测试工具以供多种工具使用,则可以从另一个文件中获取数组的内容。哎呀,mapfile
可能是填充数组的好方法。