unit test bash 删除超过一定天数的文件的脚本函数

unit test bash script function which deletes files older than certain number of days

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

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

是否可以对上述功能进行单元测试,因为它有复杂的命令?如果不可能,我们可以用其他方式重写上面的函数,以便它可以进行单元测试。请指教

在我看来,您问的是三个不同的问题:

  1. 我的代码好用吗?
  2. 如何为 BASH
  3. 编写一般测试
  4. 如何测试此特定代码?

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

这个命令并没有那么复杂。但即使是,您也会测试代码的 side-effect,而不是代码本身。所以代码的复杂性甚至并不重要...

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

@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 命令可以 运行 正常 as-is,无需包裹在 eval.

  • 没有检查。 None。完全没有。您可能需要 至少 检查是否确实提供了 </code>。你<em>也可以</em>检查它是否是一个整数。</p> </li> <li><p>您可以检查 <code>test-files 是否确实存在

  • test-files目录是hard-coded。我会把它作为函数的参数。这样就可以为测试提供与真实路径不同的路径。

这些变化看起来像这样:

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  days in ${path}"

    find "${path}" -mtime "+" -exec rm {} \;
  fi
}

当然,现在代码多了,测试也应该多了。我将把它留作 reader.

的练习

如果您还不熟悉它,您可能想看看 shellcheck。如果您编写任何可能导致问题的代码,它会警告您。

您可能还想查看 shfmt(来自 mvdan.cc/sh 包)以格式化 shell 脚本。