我正在尝试在我的多线程程序中实现一个记录器。所以我尝试使用
std::io::stdout
来获得 StdoutLock 以确保原子性。但后来我发现这样一来,cargo test
时,所有写入stdout的日志都无法被捕获。
我写了一个演示:
use std::io::Write as _;
pub fn print() {
println!("Hello, world! (print)");
}
pub fn write() {
let mut handle = std::io::stdout().lock();
writeln!(&mut handle, "Hello, world! (write)").unwrap();
handle.flush().unwrap();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_print() {
print();
}
#[test]
fn test_write() {
write();
}
}
运行
cargo test
时,会打印:
$ cargo test --lib
running 2 tests
Hello, world! (write)
test tests::test_print ... ok
test tests::test_write ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
我想知道如何避免在运行测试时打印
"Hello, world! (write)"
。
libtest 对 stdout 的捕获确实没有考虑
stdout()
,这是 issue #90785。
理想情况下,这将在 std 中修复;在那之前,您可以制作一个基于
cfg(test)
的包装器,在 println!()
和 stdout().lock()
之间切换:
use std::io::{self, Write};
pub struct Stdout {
#[cfg(not(test))]
inner: std::io::StdoutLock<'static>,
}
impl Stdout {
pub fn lock() -> Self {
Self {
#[cfg(not(test))]
inner: std::io::stdout().lock(),
}
}
}
impl Write for Stdout {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
#[cfg(not(test))]
{
self.inner.write(buf)
}
#[cfg(test)]
{
println!("{}", std::str::from_utf8(buf).expect("non-UTF8 print"));
Ok(buf.len())
}
}
fn flush(&mut self) -> io::Result<()> {
#[cfg(not(test))]
{
self.inner.flush()
}
#[cfg(test)]
{
Ok(())
}
}
}
pub fn write() {
let mut handle = Stdout::lock();
writeln!(&mut handle, "Hello, world! (write)").unwrap();
// println!("Hello, world! (write)");
handle.flush().unwrap();
}
但这在集成测试中不起作用,因为它们没有设置
cfg(test)
。