Tại sao không println! làm việc trong các bài kiểm tra đơn vị Rust?


284

Tôi đã thực hiện phương pháp và kiểm tra đơn vị sau:

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

Tôi chạy thử nghiệm đơn vị theo cách này:

rustc --test app.rs; ./app

Tôi cũng có thể chạy cái này với

cargo test

Tôi nhận được một tin nhắn nói rằng bài kiểm tra đã qua nhưng println!nó không bao giờ được hiển thị trên màn hình. Tại sao không?

Câu trả lời:


327

Điều này xảy ra bởi vì các chương trình thử nghiệm của Rust che giấu sự xuất hiện của các thử nghiệm thành công để đầu ra thử nghiệm được gọn gàng. Bạn có thể vô hiệu hóa hành vi này bằng cách chuyển --nocapturetùy chọn sang nhị phân thử nghiệm hoặc tới cargo test:

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

Yêu cầu kiểm tra:

% 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

Tuy nhiên, nếu các thử nghiệm thất bại, thiết bị xuất chuẩn của chúng sẽ được in bất kể tùy chọn này có hay không.


10
Bạn đã đề cập đến việc chuyển --nocapturetùy chọn sang cargo test, nhưng hàng hóa không nhận ra lá cờ này cho tôi (sử dụng hàng đêm mới nhất từ ​​Rustup.sh). Bạn có chắc chắn nó nên hoạt động?
Jim Garrison

42
@JimGarrison, thực sự, có một vấn đề về điều đó. Trong khi đó bạn có thể sử dụng cargo test -- --nocapture, nó nên hoạt động.
Vladimir Matveev

4
cảm ơn! không liên quan đến câu hỏi này, nhưng điều đó cũng giúp tôi tìm ra cách để đi cargo test [--] --benchlàm quá!
Jim Garrison

6
@Nashenas, tùy chọn được gọi nocapture, không no-capture.
Vladimir Matveev

1
Có ai đã tìm ra cách in khi gỡ lỗi trong Visual Studio Code trong windows chưa? Tác vụ sau không in ra trình bao bật lên: trình gỡ lỗi "kiểm tra hàng hóa - không chạy - --nocapture". Lưu ý việc sử dụng đối số không chạy mặc dù dường như nó không tạo ra sự khác biệt. Tất cả những gì tôi thấy là "chạy thử nghiệm 1". Dụng cụ vụng về.
David

75

TL; DR

$ cargo test -- --nocapture

Với đoạn mã sau:

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

Sau đó chạy như sau:

 $ cargo test -- --nocapture

Và bạn sẽ thấy

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-capturecông việc ngắn hạn. Tôi nhận được lỗi sau:thread '<main>' panicked at '"Unrecognized option: \'no-capture\'."', ../src/libtest/lib.rs:249
Nashenas

Tôi tự hỏi nếu vấn đề này github.com/rust-lang/cargo/issues/1377 là vấn đề?
siêu thực

5
Như đã được chỉ ra trong các ý kiến ​​trước đó, tùy chọn là --nocapture, không --no-capture. Tuy nhiên, đó là một sai lầm hoàn toàn rõ ràng để đưa ra hầu hết các quy ước dòng lệnh mà chúng ta có xu hướng bắt gặp. Tôi chỉ sử dụng tùy chọn này chính xác như được mô tả trong câu trả lời này trong rỉ sét 1.1 (hàng hóa 0.2.0) và nó hoạt động chính xác như quảng cáo.
Glenn McAllister

10

Để bao gồm in ra println!()và giữ màu cho kết quả kiểm tra, hãy sử dụng colorvà gắn nocapturecờ vào cargo test.

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

(phiên bản chở hàng: 0.13.0 hàng đêm)


6

Trong khi thử nghiệm, đầu ra tiêu chuẩn không được hiển thị. Không sử dụng tin nhắn văn bản để thử nghiệm nhưng assert!, assert_eq!fail!thay thế. Hệ thống kiểm tra đơn vị của Rust có thể hiểu những điều này nhưng không phải là tin nhắn văn bản.

Bài kiểm tra bạn đã viết sẽ vượt qua ngay cả khi có sự cố. Hãy xem tại sao:

read_to_endchữ ký của fn read_to_end(&mut self) -> IoResult<Vec<u8>>

Nó trả về một IoResultđể chỉ thành công hoặc lỗi. Đây chỉ là một loại def cho Resultgiá trị lỗi là một IoError. Tùy bạn quyết định cách xử lý lỗi. Trong trường hợp này, chúng tôi muốn tác vụ thất bại, được thực hiện bằng cách gọi unwrapvào Result.

Điều này sẽ làm việc:

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

unwrap không nên quá lạm dụng

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.