如何在测试中检查std :: process :: exit()的退出代码?

时间:2017-04-13 11:24:41

标签: rust

在Rust测试中,有没有办法检查调用std::process::exit()的函数是否真的用特定的退出代码终止了进程?

受挫的例子:

fn foo(n: i32) {
    std::process::exit(n);
}

#[test]
fn exits_with_correct_exit_code() {
    // How do I assert that the following call terminates
    // the process with exit code 1?
    foo(1);
}

1 个答案:

答案 0 :(得分:3)

你做不到。 std::process:exit的名字很有名,但是如果不清楚它的作用是什么方式:

  

使用指定的退出代码终止当前进程。

     

此功能永远不会返回并立即终止   目前的过程。退出代码将传递到底层操作系统   并可供其他流程使用。

     

请注意,因为此函数永远不会返回,并且它会终止   进程,当前堆栈或任何其他线程没有析构函数   堆栈将运行。如果需要干净关机,建议使用   只在没有更多的已知点调用此函数   破坏者离开了。

运行测试时,每个测试都在一个单独的线程中运行,但所有测试都在一个进程中运行。当该过程终止时,测试就随之进行。

您可以尝试进行一些复杂的递归测试:

#[test]
#[ignore]
fn real() {
    std::process::exit(42)
}

#[test]
fn shim() {
    let status = std::process::Command::new("/proc/self/exe")
        .args(&["--ignored", "real"])
        .status()
        .expect("Unable to run program");

    assert_eq!(Some(42), status.code());
}

这有特定于平台的代码来查找当前进程,但它可以正常工作"。

老实说,我说代码超出了测试范围。你不应该测试std::process::exit做了它会说的那样。如果你真的需要断言用一个参数调用一个函数,那就是mock object的用途。

使用依赖注入来提供闭包,捕获闭包中的值,并编写一个薄的垫片:

fn foo_logic<F>(n: i32, f: F)
    where F: FnOnce(i32)
{
    f(n);
}

fn foo(n: i32) {
    foo_logic(n, |n| std::process::exit(n));
}

#[test]
fn exits_with_correct_exit_code() {
    let mut value = None;
    foo_logic(1, |v| value = Some(v));
    assert_eq!(Some(1), value);
}

您也可以考虑提取计算潜在错误代码并直接测试的逻辑。