I strongly recommend against doing this, but if you are using nightly and don't mind using a feature that seems unlikely to ever be stabilized, you can directly capture stdout and stderr using hidden functionality of the standard library:
#![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");
}
It's very rare that a function "cannot be changed", so I'd encourage you to do so and use dependency injection instead. For example, if you are able to edit foo
but do not want to change its signature, move all the code to a new function with generics which you can test directly:
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(())
}
See also: