为什么不打印!

Why doesn't println! work in Rust unit tests?

我已经实现了以下方法和单元测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
use std::fs::File;
use std::path::Path;
use std::io::prelude::*;

fn read_file(path: &Path) {
    let mut file = File::open(path).unwrap();
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    println!("{}", contents);
}

#[test]
fn test_read_file() {
    let path = &Path::new("/etc/hosts");
    println!("{:?}", path);
    read_file(path);
}

我以这种方式运行单元测试:

1
rustc --test app.rs; ./app

我也可以用

1
cargo test

我收到一条消息,说测试通过了,但屏幕上永远不会显示println!。为什么不呢?


这是因为生锈测试程序将标准输出隐藏在成功的测试中,以便测试输出整洁。通过将--nocapture选项传递给测试二进制文件或cargo test选项,可以禁用此行为:

1
2
3
4
#[test]
fn test() {
    println!("Hidden output")
}

调用测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
% rustc --test main.rs; ./main

running 1 test
test test ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured

% ./main --nocapture

running 1 test
Hidden output
test test ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured

% cargo test -- --nocapture

running 1 test
Hidden output
test test ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured

但是,如果测试失败,无论是否存在此选项,都将打印它们的stdout。


DR

1
$ cargo test -- --nocapture

使用以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum PieceShape {
    King, Queen, Rook, Bishop, Knight, Pawn
}

fn main() {
    println!("Hello, world!");
}

#[test]
fn demo_debug_format() {
    let q = PieceShape::Queen;
    let p = PieceShape::Pawn;
    let k = PieceShape::King;
    println!("q={:?} p={:?} k={:?}", q, p, k);
}

然后运行以下程序:

1
 $ cargo test -- --nocapture

你应该看到

1
2
3
4
5
6
7
Running target/debug/chess-5d475d8baa0176e4

running 1 test
q=Queen p=Pawn k=King
test demo_debug_format ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured


使用cargo test中的colornocapture标志,包括使用println!()打印并保留测试结果的颜色。

1
$ cargo test -- --color always --nocapture

(货物版本:每晚0.13.0)


测试时,不显示标准输出。不要使用文本消息进行测试,而是使用assert!assert_eq!fail!。Rust的单元测试系统可以理解这些信息,但不能理解文本消息。

即使出了问题,你所写的测试也会通过。让我们看看原因:

read_to_end的签名是江户十一〔四〕号

它返回一个IoResult来表示成功或错误。这只是Result的类型def,其错误值为IoError。由您决定如何处理错误。在这种情况下,我们希望任务失败,这是通过调用Result上的unwrap来完成的。

这将起作用:

1
2
3
let contents = File::open(&Path::new("message.txt"))
    .read_to_end()
    .unwrap();

不过,不应过度使用unwrap