5

我有一个 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++ 中以某种方式将该字符串拆分为参数(至少正确处理空格和引号)。

4

2 回答 2

9

运行时涉及两个Rust 工具链。cargo test

cargo test它本身会在您的包或工作区中查找所有可测试的目标,使用 构建它们cfg(test),然后运行这些二进制文件。cargo test处理 左边的--参数,右边的参数被传递给二进制文件。

然后,

测试是使用创建可执行文件的--test选项构建的,该选项具有自动运行在多个线程中使用 #[test] 属性注释的所有函数的函数。带注释的函数也将在一次迭代中运行,以验证它们是否正常工作。rustcmain#[bench]

可以通过在目标清单设置中进行设置来禁用 libtest 工具harness = false,在这种情况下,您的代码将需要提供自己的main函数来处理正在运行的测试。

“libtest 工具”拒绝您的额外参数。就您而言,由于您打算运行整个其他测试套件,因此我认为禁用该工具是合适的。

  1. 将您的委托代码移动到它自己的文件中,通常位于tests/您的包目录中:

    Cargo.toml
    src/
        lib.rs
        ...
    tests/
        cpp_test.rs
    
  2. 为它写一个明确的目标部分Cargo.toml禁用线束:

    [[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. cpp_test.rs中,不要编写具有该#[test]属性的函数,而是编写一个main读取env::args()和调用 C++ 测试的普通函数。

[免责声明:我熟悉这些机制,因为我使用了 Criterion 基准测试(这同样需要禁用默认工具),但我实际上并没有按照您正在寻找的方式编写带有自定义参数的测试。所以,有些细节可能是错误的。如果有任何需要纠正的地方,请告诉我。]

于 2021-01-19T15:09:38.110 回答
1

除了Kevin Reid 的回答之外,如果您不想编写自己的测试工具,可以使用shell-wordscrate将环境变量拆分为遵循 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");
于 2021-01-20T07:32:49.720 回答