You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bash测试中能否Mock内置command命令?环境依赖脚本如何测试?

问题:如何在Bats中Stub内置命令并测试依赖检查脚本?

我有一个脚本会在出错时检查所有依赖是否已安装,为此使用了内置的command命令。最简版本脚本script_to_test.sh如下:

command -v pdfgrep
return $?

我使用bats-core编写了测试文件test.sh:

setup() {
  load 'test_helper/bats-support/load'
  load 'test_helper/bats-assert/load'
  load 'test_helper/mocks/stub'
  DIR="$( cd "$( dirname "$BATS_TEST_FILENAME" )" >/dev/null 2>&1 && pwd )"
  PATH="$DIR/..:$PATH"
}

@test "Test mocking built-ins" {
  stub command \
    "-v pdfgrep : exit 17"
  run script_to_test.sh
  unstub command
  assert_failure 17
}

运行测试时出现报错:

`unstub command' failed

原因是被stub的command从未被调用。请问:是否可以Stub内置命令?如何测试依赖环境的脚本行为?


解答

能不能Stub内置命令?

不能直接用bats-mock的stub命令处理Shell内置命令。因为stub的原理是在PATH中添加优先级更高的伪造可执行文件,但Shell内置命令(比如command、echo)会直接被Shell执行,不会去PATH中查找外部命令,所以你的mock版本根本不会被触发,这就是报错的原因。

如何测试这类依赖检查脚本?

提供两种可行的解决方案:

方案1:修改被测脚本,引入可替换的检查命令变量

修改script_to_test.sh,把内置的command换成可通过环境变量覆盖的变量,不影响正常使用,仅在测试时替换:

# script_to_test.sh
# 默认使用内置command,测试时可通过环境变量替换
CHECK_CMD="${CHECK_CMD:-command}"
$CHECK_CMD -v pdfgrep
return $?

对应的Bats测试代码:

@test "Test dependency not found" {
  # 用stub创建伪造的check_cmd命令
  stub check_cmd \
    "-v pdfgrep : exit 17"
  # 让脚本使用伪造的命令执行检查
  CHECK_CMD="check_cmd" run script_to_test.sh
  unstub check_cmd
  assert_failure 17
}

方案2:在子Shell中用函数覆盖内置命令

不需要修改被测脚本,利用Shell函数可以覆盖内置命令的特性,在执行脚本的子Shell中定义mock函数:

@test "Test dependency not found with function mock" {
  # 在子Shell中定义mock的command函数,仅对当前测试生效
  run bash -c '
    command() {
      # 匹配目标调用参数时返回指定退出码
      if [[ "$*" == "-v pdfgrep" ]]; then
        exit 17
      fi
      # 其他情况调用真实的内置command
      builtin command "$@"
    }
    # 加载并执行被测脚本
    source script_to_test.sh
  '
  assert_failure 17
}

这种方式的优势是无需改动生产脚本,但要注意:必须在子Shell中定义mock函数,避免污染全局测试环境;如果脚本中command有其他用法,需要在mock函数中处理,或者用builtin command "$@"兜底调用真实命令。


内容的提问来源于stack exchange,提问作者Pascal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 00:40:02