ทำไมไม่พิมพ์! ทำงานในการทดสอบหน่วยสนิมหรือไม่


285

ฉันใช้วิธีและการทดสอบหน่วยต่อไปนี้แล้ว:

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

ฉันรันการทดสอบหน่วยด้วยวิธีนี้:

rustc --test app.rs; ./app

ฉันยังสามารถเรียกใช้ด้วย

cargo test

ฉันได้รับข้อความแจ้งว่าผ่านการทดสอบ แต่println!ไม่ปรากฏบนหน้าจอ ทำไมจะไม่ล่ะ?

คำตอบ:


327

สิ่งนี้เกิดขึ้นเนื่องจากโปรแกรมทดสอบสนิมซ่อน stdout ของการทดสอบที่สำเร็จเพื่อให้ผลลัพธ์การทดสอบเป็นระเบียบเรียบร้อย คุณสามารถปิดการทำงานนี้ได้โดยส่ง--nocaptureตัวเลือกไปที่ไบนารีทดสอบหรือไปที่cargo test:

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

การเรียกใช้การทดสอบ:

% 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

หากการทดสอบล้มเหลว stdout ของพวกเขาจะถูกพิมพ์โดยไม่คำนึงว่ามีตัวเลือกนี้อยู่หรือไม่


10
คุณพูดถึงการส่ง--nocaptureตัวเลือกไปยังcargo testแต่สินค้าไม่รู้จักการตั้งค่าสถานะนี้สำหรับฉัน (ใช้ล่าสุดทุกคืนจาก rustup.sh) คุณแน่ใจหรือว่ามันควรจะทำงาน?
Jim Garrison

42
@ JimGarrison แน่นอนมีปัญหาในเรื่องนั้น ในขณะที่คุณสามารถใช้cargo test -- --nocaptureมันควรจะทำงาน
Vladimir Matveev

4
ขอบคุณ! ไม่เกี่ยวข้องกับคำถามนี้ แต่นั่นก็ช่วยให้ฉันเข้าใจวิธีcargo test [--] --benchทำงานเช่นกัน!
Jim Garrison

6
@Nashenas ตัวเลือกที่เรียกว่าไม่nocapture no-capture
Vladimir Matveev

1
มีใครคิดวิธีการพิมพ์เมื่อตรวจแก้จุดบกพร่องในรหัส Visual Studio ใน windows? งานต่อไปนี้ไม่ได้พิมพ์ลงในเชลล์ป๊อปอัพ: "debugger" cargo test - no-run - - noocapture " สังเกตการใช้อาร์กิวเมนต์ที่ไม่มีการรันแม้ว่าจะไม่ได้สร้างความแตกต่างในทางใดทางหนึ่ง สิ่งที่ฉันเห็นคือ "การทดสอบ 1 ครั้ง" เครื่องมือช่างน่าอึดอัดใจ
David

75

TL; DR

$ cargo test -- --nocapture

ด้วยรหัสต่อไปนี้:

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

จากนั้นเรียกใช้สิ่งต่อไปนี้:

 $ cargo test -- --nocapture

และคุณควรเห็น

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-captureไม่ทำงานอีกต่อไป ฉันได้รับข้อผิดพลาดดังต่อไปนี้:thread '<main>' panicked at '"Unrecognized option: \'no-capture\'."', ../src/libtest/lib.rs:249
Nashenas

ฉันสงสัยว่าปัญหานี้github.com/rust-lang/cargo/issues/1377เป็นปัญหาหรือไม่
superlogical

5
ที่ได้รับการชี้ให้เห็นในความคิดเห็นก่อนหน้านี้ตัวเลือกที่ไม่--nocapture --no-captureอย่างไรก็ตามนั่นเป็นข้อผิดพลาดที่ชัดเจนอย่างชัดเจนที่จะทำให้การประชุมบรรทัดคำสั่งส่วนใหญ่ที่เรามักพบ ฉันเพิ่งใช้ตัวเลือกนี้ตรงตามที่อธิบายไว้ในคำตอบนี้ในสนิม 1.1 (ขนส่งสินค้า 0.2.0) และมันทำงานตามที่โฆษณาไว้
Glenn McAllister

10

ที่จะรวมลึกหนาบางพิมพ์ด้วยprintln!()และให้สีสำหรับผลการทดสอบใช้colorและธงnocapturecargo test

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

(รุ่นขนส่งสินค้า: 0.13.0 ทุกคืน)


6

ในขณะที่การทดสอบเอาต์พุตมาตรฐานจะไม่ปรากฏขึ้น อย่าใช้ข้อความสำหรับการทดสอบ แต่assert!, assert_eq!และfail!แทน ระบบทดสอบหน่วยของสนิมสามารถเข้าใจสิ่งเหล่านี้ได้ แต่ไม่ใช่ข้อความ

การทดสอบที่คุณเขียนจะผ่านแม้ว่าจะมีบางอย่างผิดปกติ มาดูกันว่าทำไม:

read_to_endลายเซ็นต์คือ fn read_to_end(&mut self) -> IoResult<Vec<u8>>

มันจะส่งกลับIoResultเพื่อบ่งชี้ความสำเร็จหรือข้อผิดพลาด นี่เป็นเพียง def ชนิดหาค่าความผิดพลาดซึ่งเป็นResult IoErrorขึ้นอยู่กับคุณที่จะตัดสินใจว่าจะจัดการข้อผิดพลาดอย่างไร ในกรณีนี้เราต้องการงานที่จะล้มเหลวที่จะทำโดยการโทรบนunwrapResult

สิ่งนี้จะได้ผล:

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

unwrap ไม่ควรใช้มากเกินไป

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.