Perché non stampare! lavorare nei test unitari di Rust?


286

Ho implementato il seguente metodo e 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);
}

Eseguo il test dell'unità in questo modo:

rustc --test app.rs; ./app

Potrei anche eseguirlo con

cargo test

Ricevo un messaggio che dice che il test è stato superato ma println!non viene mai visualizzato sullo schermo. Perchè no?

Risposte:


328

Ciò accade perché i programmi di test Rust nascondono lo stdout di test riusciti affinché l'output del test sia ordinato. È possibile disabilitare questo comportamento passando l' --nocaptureopzione al binario di prova o a cargo test:

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

Invocare i test:

% 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 i test falliscono, tuttavia, il loro stdout verrà stampato indipendentemente dal fatto che questa opzione sia presente o meno.


10
Hai detto di passare l' --nocaptureopzione a cargo test, ma il carico non riconosce questa bandiera per me (usando l'ultima notte da rustup.sh). Sei sicuro che dovrebbe funzionare?
Jim Garrison,

42
@JimGarrison, in effetti, c'è un problema al riguardo. Nel frattempo puoi usare cargo test -- --nocapture, dovrebbe funzionare.
Vladimir Matveev,

4
Grazie! estraneo a questa domanda, ma ciò mi ha anche aiutato a capire come mettermi cargo test [--] --benchal lavoro!
Jim Garrison,

6
@Nashenas, l'opzione è chiamata nocapture, no no-capture.
Vladimir Matveev,

1
Qualcuno ha capito come stampare durante il debug in Visual Studio Code in Windows? La seguente attività non viene stampata sulla shell popup: debugger "test cargo --no-run - --nocapture". Nota l'uso dell'argomento no-run sebbene non sembri fare la differenza in entrambi i modi. Tutto quello che vedo è "in esecuzione 1 test". Strumenti scomodi.
David,

75

TL; DR

$ cargo test -- --nocapture

Con il seguente codice:

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

Quindi eseguire quanto segue:

 $ cargo test -- --nocapture

E dovresti vedere

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 -- --no-capturenon lavora più. Ottengo il seguente errore:thread '<main>' panicked at '"Unrecognized option: \'no-capture\'."', ../src/libtest/lib.rs:249
Nashenas,

Mi chiedo se questo problema github.com/rust-lang/cargo/issues/1377 sia il problema?
superlogico

5
Come è stato sottolineato nei commenti precedenti, l'opzione è --nocaptureno --no-capture. Tuttavia, questo è un errore del tutto ovvio nel dare la maggior parte delle convenzioni da riga di comando che tendiamo a incontrare. Ho appena usato questa opzione esattamente come descritto in questa risposta nella ruggine 1.1 (carico 0.2.0) e ha funzionato esattamente come pubblicizzato.
Glenn McAllister,

11

Per includere stampe con println!()e conservare i colori per i risultati del test, utilizzare i flag colore nocapturein cargo test.

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

(versione cargo: 0.13.0 per notte)


6

Durante il test, l'output standard non viene visualizzato. Non utilizzare i messaggi di testo per il test, ma assert!, assert_eq!e fail!invece. Il sistema di test unitari di Rust è in grado di comprendere questi ma non i messaggi di testo.

Il test che hai scritto passerà anche se qualcosa va storto. Vediamo perché:

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

Restituisce un IoResultper indicare successo o errore. Questo è solo un tipo def per a il Resultcui valore di errore è un IoError. Sta a te decidere come gestire un errore. In questo caso, vogliamo che l'attività fallisca, il che viene fatto chiamando unwrapil Result.

Questo funzionerà:

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

unwrap non dovrebbe essere abusato però.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.