Rust CLI测试框架assert_cli的使用:高效命令行应用断言与测试工具

Rust CLI测试框架assert_cli的使用:高效命令行应用断言与测试工具

Assert CLI

测试CLI应用程序 - 该crate用于检查子进程的输出是否符合预期。

注意:assert_cli当前形式已被弃用。assert_cli的精神继承者是assert_cmd

许可证

根据以下任一许可:

  • Apache许可证,版本2.0
  • MIT许可证

安装

全局安装

cargo install assert_cli

作为库安装

在项目目录中运行以下Cargo命令:

cargo add assert_cli

或者在Cargo.toml中添加:

assert_cli = "0.6.3"

完整示例代码

extern crate assert_cli;

#[test]
fn test_cli_output() {
    // 测试命令是否成功执行
    assert_cli::Assert::command(&["echo", "Hello World"])
        .succeeds()
        .stdout().contains("Hello World")
        .unwrap();
    
    // 测试命令是否失败
    assert_cli::Assert::command(&["false"])
        .fails()
        .unwrap();
        
    // 测试包含特定错误输出
    assert_cli::Assert::command(&["ls", "nonexistent_file"])
        .fails()
        .stderr().contains("No such file or directory")
        .unwrap();
        
    // 测试带有环境变量的命令
    assert_cli::Assert::command(&["printenv", "HOME"])
        .with_env(&[("HOME", "/custom/home")])
        .succeeds()
        .stdout().is("/custom/home\n")
        .unwrap();
}

维护者

  • Pascal Hertleif (killercup)
  • Ed Page (epage)

类别

  • 开发工具::测试

扩展示例代码

extern crate assert_cli;

#[test]
fn test_cli_advanced() {
    // 测试命令执行时间
    assert_cli::Assert::command(&["sleep", "1"])
        .takes_less_than(Duration::from_secs(2))
        .unwrap();
        
    // 测试命令退出码
    assert_cli::Assert::command(&["grep", "pattern", "nonexistent_file"])
        .fails_with(2)  // grep退出码2表示文件不存在
        .unwrap();
        
    // 测试正则表达式匹配输出
    assert_cli::Assert::command(&["date", "+%Y"])
        .succeeds()
        .stdout().matches(r"\d{4}")  // 匹配4位数字年份
        .unwrap();
        
    // 测试管道输入
    assert_cli::Assert::command(&["wc", "-l"])
        .with_stdin("line1\nline2\nline3")
        .succeeds()
        .stdout().contains("3")
        .unwrap();
}

1 回复

Rust CLI测试框架assert_cli的使用:高效命令行应用断言与测试工具

assert_cli是一个用于测试命令行应用程序的Rust库,它提供了一组简洁的断言来验证命令行程序的输出、退出状态和行为。

安装方法

在Cargo.toml中添加依赖:

[dev-dependencies]
assert_cli = "0.6"

基本使用方法

1. 简单命令执行测试

#[test]
fn test_hello_world() {
    assert_cli::Assert::command(&["echo", "Hello, world!"])
        .stdout().is("Hello, world!")
        .unwrap();
}

2. 测试退出状态码

#[test]
fn test_exit_code() {
    // 测试成功退出(0)
    assert_cli::Assert::command(&["true"])
        .succeeds()
        .unwrap();
    
    // 测试非零退出
    assert_cli::Assert::command(&["false"])
        .fails()
        .unwrap();
}

3. 测试部分输出匹配

#[test]
fn test_partial_output() {
    assert_cli::Assert::command(&["ls"])
        .stdout().contains("Cargo.toml")  // 检查输出是否包含特定字符串
        .unwrap();
}

4. 测试环境变量和当前目录

#[test]
fn test_with_env() {
    assert_cli::Assert::command(&["printenv", "MY_VAR"])
        .with_env(&[("MY_VAR", "test_value")])
        .stdout().is("test_value")
        .unwrap();
}

5. 测试标准错误输出

#[test]
fn test_stderr() {
    assert_cli::Assert::command(&["ls", "nonexistent_directory"])
        .stderr().contains("No such file or directory")
        .fails()
        .unwrap();
}

6. 测试超时

#[test]
fn test_timeout() {
    assert_cli::Assert::command(&["sleep", "10"])
        .timeout(1)  // 设置1秒超时
        .fails()
        .unwrap();
}

高级用法

1. 测试管道操作

#[test]
fn test_pipeline() {
    assert_cli::Assert::command(&["echo", "hello"])
        .pipe(&["tr", "a-z", "A-Z"])
        .stdout().is("HELLO")
        .unwrap();
}

2. 测试二进制程序

#[test]
fn test_my_cli_tool() {
    // 假设你的CLI工具名为my-cli
    assert_cli::Assert::main_binary()
        .with_args(&["--help"])
        .stdout().contains("Usage:")
        .succeeds()
        .unwrap();
}

3. 使用正则表达式匹配输出

#[test]
fn test_regex_match() {
    assert_cli::Assert::command(&["date"])
        .stdout().matches(r"\d{4}-\d{2}-\d{2}")  // 匹配日期格式
        .unwrap();
}

完整示例demo

下面是一个综合使用assert_cli测试CLI工具的完整示例:

// tests/cli_tests.rs

#[cfg(test)]
mod tests {
    use assert_cli::Assert;

    #[test]
    fn test_cli_help() {
        // 测试帮助命令
        Assert::main_binary()
            .with_args(&["--help"])
            .stdout().contains("Usage:")
            .succeeds()
            .unwrap();
    }

    #[test]
    fn test_cli_version() {
        // 测试版本命令
        Assert::main_binary()
            .with_args(&["--version"])
            .stdout().contains("1.0.0")  // 假设版本号为1.0.0
            .succeeds()
            .unwrap();
    }

    #[test]
    fn test_cli_with_input() {
        // 测试带输入参数的命令
        Assert::main_binary()
            .with_args(&["process", "--input", "test.txt"])
            .stdout().contains("Processing file: test.txt")
            .succeeds()
            .unwrap();
    }

    #[test]
    fn test_cli_error_handling() {
        // 测试错误处理
        Assert::main_binary()
            .with_args(&["process", "--input", "nonexistent.txt"])
            .stderr().contains("File not found")
            .fails()
            .unwrap();
    }

    #[test]
    fn test_cli_with_env() {
        // 测试环境变量
        Assert::main_binary()
            .with_args(&["config"])
            .with_env(&[("APP_ENV", "test")])
            .stdout().contains("Environment: test")
            .succeeds()
            .unwrap();
    }

    #[test]
    fn test_cli_output_format() {
        // 测试输出格式
        Assert::main_binary()
            .with_args(&["list"])
            .stdout().matches(r"ID:\s+\d+")  // 匹配ID: 后跟数字的格式
            .succeeds()
            .unwrap();
    }
}

最佳实践

  1. 隔离测试:每个测试应该独立运行,不依赖其他测试的状态
  2. 明确断言:尽量使用最具体的断言(如精确字符串匹配而非包含)
  3. 清理资源:如果测试创建了临时文件或目录,确保测试后清理
  4. 并行安全:确保测试可以安全地并行运行

assert_cli是测试Rust命令行工具的强大助手,它能帮助你确保CLI应用在各种情况下的行为符合预期。

回到顶部