单元测试bash脚本功能,删除超过一定天数的文件



我没有太多bash/shell脚本编写经验,最近才开始使用Bats框架或库编写一些带有单元测试的bash脚本。目前正在编写一个脚本,需要删除超过一定天数的文件。函数如下:

function deleteFilesOlderThan() {
echo "Deleting files older than $1 days"
eval "find ./test-files -mtime +$1 -exec rm {} ;"
}

上面的函数有复杂的命令,是否可以进行单元测试?如果不可能,我们可以用其他方式重写上面的函数,使它是单元可测试的。请建议。

从我的角度来看,你问了三个独立的问题:

  1. 我的代码好吗?
  2. 如何为BASH编写测试
  3. 我如何测试这个特定的代码?

因为这听起来更像是一个代码审查的请求,它可能更适合https://codereview.stackexchange.com/,但我还是在这里回答…

这个命令其实没那么复杂。但即使是这样,测试的也是代码的副作用,而不是代码本身。所以代码的复杂性并不重要…

无论如何,测试应该是这样的:

@test "deleteFilesOlderThan deletes files" {
# Arrange
touch -t 123412312345 ./test-files/test.txt
# Act
deleteFilesOlderThan 1000
# Assert
[ ! -f ./test-files/test.txt ]
}

您可以添加更多的测试,例如使用assert_output检查输出,并检查较新的文件是否没有被删除。

代码可以在不重写的情况下进行测试,但是代码中存在一些潜在的问题:

  • 如评论中所述,eval不是真正需要的。find命令可以按原样运行,而不需要在eval中包装。

  • 没有检查。一个也没有。在所有。您可能希望至少检查是否实际提供了$1还可以检查它是否是整数。

  • 你可以检查test-files是否真的存在

  • test-files目录是硬编码的。我把它作为函数的一个参数。这样就可以为测试提供不同于实际使用的路径。

这些更改看起来像这样:

function deleteFilesOlderThan() {
local days="${1:?Two parameters required: <days> <path>}"
local path="${2:?Two parameters required: <days> <path>}"

if [[ -n ${days} && ${days} = *[!0123456789]* ]]; then
echo "ERROR: Given days '${days}' is not an integer" >&2
elif [[ ! -d "${path}" ]]; then
echo "ERROR: Given path '${path}' is not a directory" >&2  
else
echo "Deleting files older than ${1} days in ${path}"
find "${path}" -mtime "+${1}" -exec rm {} ;
fi
}
当然,现在有了更多的代码,也应该有更多的测试。我将把它留给读者作为练习。

如果您还不熟悉它,您可能想检查一下shellcheck。如果你写了任何可能导致问题的代码,它会警告你。

您可能还想查看shfmt(从mvdan)。Cc/sh包)来格式化shell脚本

最新更新