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

使用shUnit2编写Shell单元测试时出现‘command not found’错误求助

问题排查:shUnit2测试脚本报错testScriptExecution: command not found

我写了一个能自动提取两次Git提交间文件变更并保存到指定目录的Shell脚本,带有日志与错误处理机制。现在为它编写带数据模拟的单元测试,但运行test_extract_delta.sh时出现如下错误:

$ ./test_extract_delta.sh
testScriptExecution
../../shunit2/shunit2/shunit2: line 1125: testScriptExecution: command not found
shunit2:ERROR testScriptExecution() returned non-zero return code.

Ran 1 test.

我的单元测试代码如下:

#!/usr/bin/env sh
# Load shUnit2
. ../../shunit2/shunit2/shunit2

# Setup mock environment
setUp() {
    # Mocking environment variables
    export EXTRACT_DELTA_CONSOLE_LOG_PATH=\"/tmp/extract_delta_console_log\"
    export MINIMIZED_CHECKOUT_ROOT=\"/tmp/minimized_checkout_root\"
    export MINIMIZED_CHECKOUT_REF=\"mock_ref\"
    export CHECKOUT_ROOT=\"/tmp/checkout_root\"
    export CHECKOUT_REF=\"mock_checkout_ref\"
    export TO_REVISION=\"mock_to_revision\"
    export FROM_REVISION=\"mock_from_revision\"
    export EXTRACTED_DELTA_ROOT=\"/tmp/extracted_delta_root\"
    export POD_NAME=\"mock_pod_name\"
    export RESULTS_FROM_COMMIT_PATH=\"/tmp/results_from_commit_path\"
    export RESULTS_TO_COMMIT_PATH=\"/tmp/results_to_commit_path\"
    export RESULTS_EXTRACTED_DELTA_REF_PATH=\"/tmp/results_extracted_delta_ref_path\"

    # Create necessary directories
    mkdir -p $EXTRACT_DELTA_CONSOLE_LOG_PATH
    mkdir -p $MINIMIZED_CHECKOUT_ROOT/$MINIMIZED_CHECKOUT_REF
    mkdir -p $CHECKOUT_ROOT/$CHECKOUT_REF
    mkdir -p $EXTRACTED_DELTA_ROOT/$POD_NAME

    # Mock git commands
    mock_git_rev_parse() {
        case \"$1\" in
        mock_from_revision) echo \"mock_from_sha\" ;;
        mock_to_revision) echo \"mock_to_sha\" ;;
        esac
    }

    mock_git_diff() {
        echo \"file1.txt\"
        echo \"file2.txt\"
        echo \"file3.txt\"
    }

    # Mock commands by overriding with functions
    git() {
        if [ \"$1\" = \"rev-parse\" ]; then
            mock_git_rev_parse \"$2\"
        elif [ \"$1\" = \"diff\" ]; then
            mock_git_diff \"$@\"
        fi
    }

    # Create mock files
    touch \"$CHECKOUT_ROOT/$CHECKOUT_REF/file1.txt\"
    touch \"$CHECKOUT_ROOT/$CHECKOUT_REF/file2.txt\"
    touch \"$CHECKOUT_ROOT/$CHECKOUT_REF/file3.txt\"

    # Create minimized checkout mock files
    touch \"$MINIMIZED_CHECKOUT_ROOT/$MINIMIZED_CHECKOUT_REF/file1.txt\"
    touch \"$MINIMIZED_CHECKOUT_ROOT/$MINIMIZED_CHECKOUT_REF/file3.txt\"
}

# Teardown mock environment
tearDown() {
    rm -rf /tmp/extract_delta_console_log
    rm -rf /tmp/minimized_checkout_root
    rm -rf /tmp/checkout_root
    rm -rf /tmp/extracted_delta_root
    rm -rf /tmp/results_from_commit_path
    rm -rf /tmp/results_to_commit_path
    rm -rf /tmp/results_extracted_delta_ref_path
}

# Test case: Run the script and verify outcomes
testScriptExecution() {
    # Run the script
    . ../scripts/extract-delta.sh

    # Check that files were copied correctly
    assertTrue \"file1.txt should exist in extracted delta path\" \"[ -f $EXTRACTED_DELTA_ROOT/$POD_NAME/file1.txt ]\"
    assertTrue \"file3.txt should exist in extracted delta path\" \"[ -f $EXTRACTED_DELTA_ROOT/$POD_NAME/file3.txt ]\"
    assertFalse \"file2.txt should not exist in extracted delta path\" \"[ -f $EXTRACTED_DELTA_ROOT/$POD_NAME/file2.txt ]\"

    # Check that commit SHAs were written to the correct paths
    assertEquals \"mock_from_sha\" \"$(cat $RESULTS_FROM_COMMIT_PATH)\"
    assertEquals \"mock_to_sha\" \"$(cat $RESULTS_TO_COMMIT_PATH)\"

    # Check that the POD_NAME was written to the correct path
    assertEquals \"mock_pod_name\" \"$(cat $RESULTS_EXTRACTED_DELTA_REF_PATH)\"
}

# Load and run shunit2
. ../../shunit2/shunit2/shunit2

问题根源

  1. 重复加载shUnit2导致测试函数丢失
    脚本开头和结尾各加载了一次../../shunit2/shunit2/shunit2。第一次加载时shUnit2会扫描并注册testScriptExecution等测试函数,但第二次加载会重置shUnit2内部状态,覆盖之前的注册信息,导致执行时找不到测试函数。

  2. 环境变量赋值的多余转义引号
    setUp中给环境变量赋值时使用了转义引号(如=\"/tmp/...\"),这会让变量值包含引号本身,后续创建目录、操作文件时会因为路径带引号而失效。

  3. mock函数的作用域问题
    mock_git_rev_parse和mock_git_diff定义在setUp内部,Shell中函数内的子函数作用域受限,外部的git函数调用它们时可能找不到,导致mock失效。


修复方案

1. 移除重复的shUnit2加载

删掉脚本开头的../../shunit2/shunit2/shunit2加载语句,只保留末尾的加载执行逻辑。

2. 去掉环境变量的多余转义引号

将setUp中的环境变量赋值改为正常格式:

export EXTRACT_DELTA_CONSOLE_LOG_PATH="/tmp/extract_delta_console_log"
export MINIMIZED_CHECKOUT_ROOT="/tmp/minimized_checkout_root"
# 其他变量同理,去掉转义的\",直接使用双引号或无引号(路径无空格时)

3. 调整mock函数作用域

把mock_git_rev_parse和mock_git_diff移到setUp外部,确保git函数能正常调用它们:

# 把mock函数移到setUp外面
mock_git_rev_parse() {
    case "$1" in
    mock_from_revision) echo "mock_from_sha" ;;
    mock_to_revision) echo "mock_to_sha" ;;
    esac
}

mock_git_diff() {
    echo "file1.txt"
    echo "file2.txt"
    echo "file3.txt"
}

setUp() {
    # ...其他代码不变
    git() {
        if [ "$1" = "rev-parse" ]; then
            mock_git_rev_parse "$2"
        elif [ "$1" = "diff" ]; then
            mock_git_diff "$@"
        fi
    }
    # ...其他代码不变
}

4. 可选:确保测试脚本有执行权限

如果还没设置执行权限,运行以下命令:

chmod +x test_extract_delta.sh

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 13:00:56