testingrustprintln

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


I've implemented the following method and unit test:

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);
}

I run the unit test this way:

rustc --test app.rs; ./app

I could also run this with

cargo test

I get a message back saying the test passed but the println! is never displayed on screen. Why not?


Solution

  • This happens because Rust test programs hide the stdout of successful tests in order for the test output to be tidy. You can disable this behavior by passing the --nocapture option to the test binary or to cargo test (but, in this case after -- – see below):

    #[test]
    fn test() {
        println!("Hidden output")
    }
    

    Invoking tests:

    % 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
    

    If tests fail, however, their stdout will be printed regardless if this option is present or not.