¿Por qué no println! trabaja en pruebas de unidad de óxido?

285

He implementado el siguiente método y prueba unitaria:

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

Ejecuto la prueba de la unidad de esta manera:

rustc --test app.rs; ./app

También podría ejecutar esto con

cargo test

Recibo un mensaje que dice que la prueba pasó pero println!que nunca se muestra en la pantalla. Por qué no?

ruipacheco
fuente

Respuestas:

327

Esto sucede porque los programas de prueba de Rust ocultan el stdout de las pruebas exitosas para que la salida de la prueba esté ordenada. Puede deshabilitar este comportamiento pasando la --nocaptureopción al binario de prueba o a cargo test:

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

Invocación de pruebas:

% 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

Sin embargo, si las pruebas fallan, su stdout se imprimirá independientemente de si esta opción está presente o no.

Vladimir Matveev
fuente
10
Usted mencionó pasar la --nocaptureopción a cargo test, pero la carga no reconoce esta bandera para mí (usando la última noche de rustup.sh). ¿Estás seguro de que debería funcionar?
Jim Garrison el
42
@JimGarrison, de hecho, hay un problema al respecto. Mientras tanto, puede usar cargo test -- --nocapture, debería funcionar.
Vladimir Matveev
44
¡Gracias! sin relación con esta pregunta, ¡pero eso también me ayudó a descubrir cómo llegar cargo test [--] --benchal trabajo también!
Jim Garrison el
66
@Nashenas, la opción se llama nocapture, no no-capture.
Vladimir Matveev
1
¿Alguien ha descubierto cómo imprimir al depurar en Visual Studio Code en Windows? La siguiente tarea no se imprime en el shell emergente: depurador "prueba de carga --no-run - --nocapture". Tenga en cuenta el uso del argumento de no ejecución, aunque no parece hacer una diferencia de ninguna manera. Todo lo que veo es "ejecutar 1 prueba". Herramientas incómodas.
David
75

TL; DR

$ cargo test -- --nocapture

Con el siguiente código:

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

Luego ejecute lo siguiente:

 $ cargo test -- --nocapture

Y deberías ver

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
superlogico
fuente
cargo test -- --no-captureYa no funciona. Me sale el siguiente error:thread '<main>' panicked at '"Unrecognized option: \'no-capture\'."', ../src/libtest/lib.rs:249
Nashenas
Me pregunto si este problema es github.com/rust-lang/cargo/issues/1377 .
superlogical
55
Como se ha señalado en comentarios anteriores, la opción es --nocaptureno --no-capture. Sin embargo, es un error completamente obvio cometer la mayoría de las convenciones de línea de comandos que tendemos a encontrar. Acabo de utilizar esta opción exactamente como se describe en esta respuesta en rust 1.1 (carga 0.2.0) y funcionó exactamente como se anuncia.
Glenn McAllister
10

Para incluir impresiones con println!()y mantener colores para los resultados de la prueba, use las banderas colory .nocapturecargo test

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

(versión de carga: 0.13.0 por noche)

nate
fuente
6

Durante la prueba, no se muestra la salida estándar. No utilizar mensajes de texto para probar, pero assert!, assert_eq!y fail!en su lugar. El sistema de prueba de la unidad de Rust puede entender esto pero no mensajes de texto.

La prueba que ha escrito pasará incluso si algo sale mal. Veamos por qué:

read_to_endla firma es fn read_to_end(&mut self) -> IoResult<Vec<u8>>

Devuelve un IoResultpara indicar éxito o error. Esto es solo un tipo def para un Resultcuyo valor de error es un IoError. Depende de usted decidir cómo se debe manejar un error. En este caso, queremos que la tarea falle, lo que se hace llamando unwrapalResult .

Esto funcionará:

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

unwrap Sin embargo, no se debe usar en exceso.

AB
fuente