Por que não imprime! trabalhar em testes de unidade Rust?

284

Implementei o seguinte método e teste de unidade:

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

Eu executo o teste de unidade desta maneira:

rustc --test app.rs; ./app

Eu também poderia executar isso com

cargo test

Recebo uma mensagem dizendo que o teste foi aprovado, mas que println!nunca é exibido na tela. Por que não?

ruipacheco
fonte

Respostas:

327

Isso acontece porque os programas de teste Rust ocultam o stdout de testes bem-sucedidos para que a saída do teste seja organizada. Você pode desativar esse comportamento, passando a --nocaptureopção para o teste de binário ou para cargo test:

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

Invocando testes:

% 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

Se os testes falharem, no entanto, seu stdout será impresso, independentemente se esta opção estiver presente ou não.

Vladimir Matveev
fonte
10
Você mencionou passar a --nocaptureopção para cargo test, mas a carga não reconhece essa sinalização para mim (usando as últimas noites do rustup.sh). Tem certeza de que deve funcionar?
Jim Garrison
42
@ JimGarrison, de fato, há um problema nisso. Enquanto isso, você pode usar cargo test -- --nocapture, deve funcionar.
Vladimir Matveev
4
obrigado! não relacionado a essa pergunta, mas isso também me ajudou a descobrir como cargo test [--] --benchtrabalhar também!
Jim Garrison
6
@ Nashenas, a opção é chamada nocapture, não no-capture.
21415 Vladimir Matveev
1
Alguém descobriu como imprimir ao depurar no Visual Studio Code no Windows? A tarefa a seguir não é impressa no shell pop-up: depurador "cargo test --no-run - --nocapture". Observe o uso do argumento sem execução, embora ele não pareça fazer diferença de qualquer maneira. Tudo o que vejo é "executando 1 teste". Ferramentas estranhas.
David
75

TL; DR

$ cargo test -- --nocapture

Com o seguinte 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);
}

Em seguida, execute o seguinte:

 $ cargo test -- --nocapture

E você deveria 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
superlógico
fonte
cargo test -- --no-capturenão funciona mais. Eu recebo o seguinte erro:thread '<main>' panicked at '"Unrecognized option: \'no-capture\'."', ../src/libtest/lib.rs:249
Nashenas
Gostaria de saber se esta questão github.com/rust-lang/cargo/issues/1377 é o problema?
Superlogical
5
Como foi apontado nos comentários anteriores, a opção é --nocapturenão --no-capture. No entanto, é um erro completamente óbvio cometer a maioria das convenções de linha de comando que tendemos a encontrar. Eu apenas usei essa opção exatamente como descrito nesta resposta na ferrugem 1.1 (carga 0.2.0) e funcionou exatamente como anunciado.
Glenn McAllister
10

Para incluir impressões println!()e manter cores nos resultados do teste, use os sinalizadores colore .nocapturecargo test

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

(versão cargo: 0.13.0 noturno)

nate
fonte
6

Durante o teste, a saída padrão não é exibida. Não use mensagens de texto para testar, mas assert!, assert_eq!e fail!em vez disso. O sistema de teste de unidade da Rust pode entender essas, mas não as mensagens de texto.

O teste que você escreveu será aprovado mesmo que algo dê errado. Vamos ver o porquê:

read_to_endA assinatura de fn read_to_end(&mut self) -> IoResult<Vec<u8>>

Retorna um IoResultpara indicar sucesso ou erro. Este é apenas um tipo def para um Resultcujo valor de erro é um IoError. Cabe a você decidir como um erro deve ser tratado. Nesse caso, queremos que a tarefa falhe, o que é feito chamando unwrapo Result.

Isso funcionará:

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

unwrap não deve ser usado em excesso.

AB
fonte