当我无法更改打印的代码时,如何捕获 stdout/stderr 的内容?

Cha*_*ong 5 rust

foo我有一个无法修改的函数,并且包含其中的代码println!eprintln!

fn foo() {
    println!("hello");
}
Run Code Online (Sandbox Code Playgroud)

调用该函数后,我必须测试它打印的内容,因此我想将 stdout/stderr 捕获到变量中。

She*_*ter 4

我强烈建议不要这样做,但如果您使用 nightly 并且不介意使用似乎不太可能稳定的功能,您可以使用标准库的隐藏功能直接捕获 stdout 和 stderr:

#![feature(internal_output_capture)]

use std::sync::Arc;

fn foo() {
    println!("hello");
    eprintln!("world");
}

fn main() {
    std::io::set_output_capture(Some(Default::default()));
    foo();
    let captured = std::io::set_output_capture(None);

    let captured = captured.unwrap();
    let captured = Arc::try_unwrap(captured).unwrap();
    let captured = captured.into_inner().unwrap();
    let captured = String::from_utf8(captured).unwrap();

    assert_eq!(captured, "hello\nworld\n");
}
Run Code Online (Sandbox Code Playgroud)

函数“无法更改”的情况非常罕见,因此我鼓励您这样做并改用依赖注入。例如,如果您能够编辑foo但不想更改其签名,请将所有代码移动到带有泛型的新函数中,您可以直接测试该泛型:

use std::io::{self, Write};

fn foo() {
    foo_inner(io::stdout(), io::stderr()).unwrap()
}

fn foo_inner(mut out: impl Write, mut err: impl Write) -> io::Result<()> {
    writeln!(out, "hello")?;
    writeln!(err, "world")?;
    Ok(())
}
Run Code Online (Sandbox Code Playgroud)

也可以看看: