向 Rust 测试传递自定义命令行参数

9

我有一个Rust测试,使用doctest将其委托给C++测试套件,并希望向其传递命令行参数。我的第一次尝试是:

// in mod ffi
pub fn run_tests(cli_args: &mut [String]) -> bool;

#[test]
fn run_cpp_test_suite() {
    let mut cli_args: Vec<String> = env::args().collect();
    if !ffi::run_tests(
        cli_args.as_mut_slice(),
    ) {
        panic!("C++ test suite reported errors");
    }
}

因为cargo test help显示

USAGE:
    cargo.exe test [OPTIONS] [TESTNAME] [-- <args>...]

我期望

cargo test -- --test-case="X"

run_cpp_test_suite 能够使用并传递 --test-case="X" 参数,但实际上并没有起作用,我收到了 error: Unrecognized option: 'test-case' 的错误信息,并且 cargo test -- --help 显示它有一组固定选项。
Usage: --help [OPTIONS] [FILTER]

Options:
        --include-ignored 
                        Run ignored and not ignored tests
        --ignored       Run only ignored tests
...

我的另一个想法是将参数传递到环境变量中,即

DOCTEST_ARGS="--test-case='X'" cargo test

但是我需要以某种方式将该字符串分割成参数(至少正确处理空格和引号),可以在Rust或C++中完成。


对于你的问题,有一个稍微有些不相关的答案 - 我们是否可以不为测试设置环境变量;如果唯一目的是将一些参数传递给单元测试?类似这样:https://dev59.com/21sV5IYBdhLWcg3wug7h? - Coder
2个回答

12
当你运行时,有两个Rust工具链涉及。 本身会查找包或工作区中所有可测试的目标,使用进行构建,并运行这些二进制文件。 处理左侧的参数,右侧的参数将传递给二进制文件。
然后,
测试使用<--test>选项构建到中,它创建一个带有main函数的可执行文件,该函数自动在多个线程中运行所有用#[test]属性注释的函数。带有<#[bench]>注释的函数也将运行一次以验证其功能性。
如果在目标清单设置中将设置为禁用,则可以禁用libtest harness,此时您的代码将需要提供自己的main函数来处理运行测试。
“libtest harness”是拒绝额外参数的工具。在您的情况下,由于您打算运行整个其他测试套件,因此我认为禁用harness是合适的。
  1. Move your delegation code to its own file, conventionally located in tests/ in your package directory:

    Cargo.toml
    src/
        lib.rs
        ...
    tests/
        cpp_test.rs
    
  2. Write an explicit target section in your Cargo.toml for it, with harness disabled:

    [[test]]
    name = "cpp_test"
    # path = "tests/cpp_test.rs"   # This is automatic; you can use a different path if you really want to.
    harness = false
    
  3. In cpp_test.rs, instead of writing a function with the #[test] attribute, write a normal main function which reads env::args() and calls the C++ tests.

【免责声明:我熟悉这些机制,因为我使用过Criterion基准测试(类似于需要禁用默认工具),但我实际上没有编写过带有自定义参数的测试,就像您所需求的那样。因此,某些细节可能是错误的。如果有任何需要更正的地方,请告诉我。】

谢谢,说实话我没想到这是可能的!我应该有时间明天检查它(然后接受答案)。 - Alexey Romanov

2
除了 Kevin Reid 的回答 之外,如果您不想编写自己的测试工具,您可以使用 shell-words crate 来按照 shell 规则将环境变量拆分为单个参数:
let args = var ("DOCTEST_ARGS").unwrap_or_else (|_| String::new());
let args = shell_words::split (&args).expect ("failed to parse DOCTEST_ARGS");

Command::new ("cpptest")
    .args (args)
    .spawn()
    .expect ("failed to start subprocess")
    .wait()
    .expect ("failed to wait for subprocess");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接