Kenapa tidak println! bekerja di tes unit Rust?

286

Saya telah menerapkan metode dan unit test berikut:

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

Saya menjalankan tes unit dengan cara ini:

rustc --test app.rs; ./app

Saya juga bisa menjalankan ini

cargo test

Saya mendapatkan pesan kembali yang mengatakan bahwa tes telah lulus tetapi println!tidak pernah ditampilkan di layar. Kenapa tidak?

ruipacheco
sumber

Jawaban:

328

Ini terjadi karena program pengujian Rust menyembunyikan stdout dari tes yang sukses agar hasil tes menjadi rapi. Anda dapat menonaktifkan perilaku ini dengan meneruskan --nocaptureopsi ke biner uji atau ke cargo test:

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

Tes pemanggilan:

% 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

Namun, jika tes gagal, stdout mereka akan dicetak terlepas dari apakah opsi ini ada atau tidak.

Vladimir Matveev
sumber
10
Anda menyebutkan melewati --nocaptureopsi untuk cargo test, tetapi kargo tidak mengenali bendera ini untuk saya (menggunakan nightly terbaru dari rustup.sh). Apakah Anda yakin itu akan berhasil?
Jim Garrison
42
@ JimGarrison, memang, ada masalah tentang itu. Sementara itu Anda dapat menggunakannya cargo test -- --nocapture, itu harus bekerja.
Vladimir Matveev
4
Terima kasih! tidak terkait dengan pertanyaan ini, tetapi itu juga membantu saya mencari cara cargo test [--] --benchuntuk bekerja juga!
Jim Garrison
6
@Nashenas, opsi ini dipanggil nocapture, bukan no-capture.
Vladimir Matveev
1
Adakah yang tahu cara mencetak saat melakukan debug dalam Visual Studio Code di windows? Tugas berikut ini tidak mencetak ke popup shell: debugger test --no-run - --nocapture ". Perhatikan penggunaan argumen tidak-lari meskipun tampaknya tidak membuat perbedaan. Yang saya lihat adalah "menjalankan 1 tes". Perkakas canggung.
David
75

TL; DR

$ cargo test -- --nocapture

Dengan kode berikut:

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

Kemudian jalankan yang berikut ini:

 $ cargo test -- --nocapture

Dan Anda harus melihatnya

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
superlogikal
sumber
cargo test -- --no-capturetidak lagi berfungsi. Saya mendapatkan kesalahan berikut:thread '<main>' panicked at '"Unrecognized option: \'no-capture\'."', ../src/libtest/lib.rs:249
Nashenas
Saya ingin tahu apakah masalah ini github.com/rust-lang/cargo/issues/1377 masalahnya?
superlogical
5
Seperti yang telah ditunjukkan dalam komentar sebelumnya, pilihannya adalah --nocapturetidak --no-capture. Namun, itu adalah kesalahan yang sangat jelas untuk membuat sebagian besar konvensi baris perintah yang cenderung kita temui. Saya hanya menggunakan opsi ini persis seperti yang dijelaskan dalam jawaban ini di karat 1.1 (kargo 0.2.0) dan bekerja persis seperti yang diiklankan.
Glenn McAllister
11

Untuk menyertakan hasil cetak dengan println!()dan menyimpan warna untuk hasil pengujian, gunakan tanda colordan nocapturemasuk cargo test.

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

(versi kargo: 0.13.0 setiap malam)

nate
sumber
6

Saat pengujian, output standar tidak ditampilkan. Jangan gunakan pesan teks untuk pengujian tetapiassert! , assert_eq!, dan fail!sebagai gantinya. Sistem pengujian unit Rust dapat memahami hal ini tetapi tidak mengirim pesan teks.

Tes yang Anda tulis akan lulus bahkan jika ada masalah. Mari kita lihat mengapa:

read_to_endTanda tangan adalah fn read_to_end(&mut self) -> IoResult<Vec<u8>>

Mengembalikan tanda IoResultuntuk menunjukkan keberhasilan atau kesalahan. Ini hanya tipe def untuk Resultnilai kesalahan yang merupakan IoError. Terserah Anda untuk memutuskan bagaimana kesalahan harus ditangani. Dalam hal ini, kami ingin tugas gagal, yang dilakukan dengan memanggilunwrap pada Result.

Ini akan berhasil:

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

unwrap seharusnya tidak digunakan secara berlebihan.

AB
sumber