30 Ngày học Rust - Day 14: Tận diệt Bug từ trứng nước bằng Automated Tests
Day 14: Viết Unit Test và Integration Test ngay trong mã nguồn. Cỗ máy Cargo tự động dọn dẹp lỗi. Tại sao ở Rust, kiểm thử không phải là tùy chọn mà là bắt buộc.

Lập trình mà không có Test là Đánh bạc mù
Bạn viết xong một hàm tính Tiền Lãi (Interest Rate) cực kì phức tạp. Bạn gọi cargo run, gõ thử 1 số vào Terminal, thấy ra đúng kết quả. Bạn tự tin Deploy lên Production. Ngày hôm sau khách hàng gõ số âm -500 vào, Web bạn đứng hình.
Để tránh những kết cục đau đớn đó, các công ty công nghệ lớn bắt buộc áp dụng Automated Tests (Kiểm thử tự động). Khác với JS phải đi mượn thư viện Jest hay Python cần pytest, Rust tích hợp hệ thống Test thẳng vào lõi Trình Biên Dịch (Built-in) cực kỳ bá đạo.

1. Unit Tests ngay trong lòng địch
Trái với truyền thống tách file Test ra thư mục xa xôi, Rust khuyên bạn viết Unit Test (Test đơn vị) Nằm ngay bên dưới cái Hàm mà bạn định Test trong cùng một file.
pub fn cong_hai_so(a: i32, b: i32) -> i32 {
a + b + 1 // Cố tình viết SAI Lỗi để xem Test nó bắt nè
}
// Bắt đầu vùng Test
#[cfg(test)]
mod tests {
use super::*; // Import tất cả code phía trên xuống vùng này
#[test]
fn thu_nghiem_tinh_tong() {
let ket_qua = cong_hai_so(2, 2);
// assert_eq! là búa tạ. Nó so sánh 2 vế. Nếu Lệch, nó Phá nát App kèm Tiếng Gào (Panic)
assert_eq!(ket_qua, 4, "Tính toán phải bằng 4 chứ thằng ngu!");
}
}Tại sao lại nhét chúng chung một cục vậy? Nhờ cái chữ #[cfg(test)], khi bạn cargo build --release đưa App lên mạng, cái Phân khu Test này bốc hơi hoàn toàn, giúp File chạy bạn mỏng tanh 0 Byte rác!
Hãy gọi: cargo test để xem phép màu: thread 'tests::thu_nghiem_tinh_tong' panicked at: Tính toán phải bằng 4 chứ thằng ngu!
2. Integration Tests (Mô phỏng Góc nhìn Đối tác)
Nếu Unit Test nằm tuốt phía trong (Dùng để bắt chẹt những file Rễ con của dự án/Hàm Private), thì Integration Tests đóng vai trò là Lão Tester Người Dùng dòm lén qua khe cửa. Lão này chỉ được phép vòi vào những Cổng API (Public pub functions).
Bạn tạo hẳn một thư mục tests ngang hàng với src. Bên trong thư mục tests, bạn quẳng vào file mới integration_test.rs:
// Giả dụ dự án bạn tên là "adder"
use adder;
#[test]
fn tinh_nang_tinh_toan_xuyen_module() {
assert_eq!(adder::cong_hai_so(5, 5), 10);
}Giờ khi gõ lại cargo test, Cargo tự động phân luồng rà qua 2 bãi chiến trường cùng lúc: [Unit tests] rồi lao xuống [Integration tests].
Câu hỏi thường gặp (FAQ)
Có cách nào Test Mảng văng Dấu Lỗi/Bắn Lỗi Panic Chủ ý không?
Có. Có những Test bạn muốn nó CHẮC CHẮN PHẢI NỔ TUNG thì mới là ĐÚNG CODE (Ví dụ test nhét số Tuổi âm -5). Chèn Macro #[should_panic] ngay dưới dòng #[test]. Từ đó, hễ Hàm Mồi không văng tung Lỗi Đỏ - Tức Test Bị Đánh Rớt Trượt.
Viết quá nhiều File Test, Cargo có chạy chậm rề Rề không?
Bí thuật đáng sợ nhất của Rust: cargo test kích hoạt các hàm test chay song song đa luồng (Multi-threading). 500 Test Cases văng vào 16 rãnh CPU của bạn. Kết quả in Cụp cực hạn 0.2 giây. (Lưu ý: Nếu có hàm Test nào Ghi Nhập Database chung bảng, Test Song Song sẽ vấp Mâu thuẫn tranh dồn vỡ cấu trúc. Bắt buộc hãm phanh đơn luồng bằng cargo test -- --test-threads=1).
Sẵn sàng cho Ngày 15? Suốt nửa chặng Đầu Khóa chúng ta Viết Ứng Dụng Console in ra mấy dòng Chữ cọc lóc. Mới Ngày Mai, Mở Hộp I/O Môi Trường, Viết Tương Tác Thật Lọc String File siêu dị qua [Day 15: I/O Programs - Viết App CLI như Grep C++ !].
Chuỗi bài viết
30 Ngày Trở Thành Rustacean Tinh Hoa
Phần 14 / 30
- Phần 1 30 Ngày học Rust - Day 1: Lời chào thế giới và Vũ khí Cargo
- Phần 2 30 Ngày học Rust - Day 2: Biến, Bất biến (Mutability) và Shadowing
- Phần 3 30 Ngày học Rust - Day 3: Luồng điều khiển (Control Flow) và sức mạnh của Match
- Phần 4 30 Ngày học Rust - Day 4: Ownership - Khái niệm định hình cỗ thần khí Rust
- Phần 5 30 Ngày học Rust - Day 5: Khóa học nhặt đồ chung với References & Borrowing
- Phần 6 30 Ngày học Rust - Day 6: Đắp nặn dự án với Structs và Methods
- Phần 7 30 Ngày học Rust - Day 7: Quyền năng vô song của Enums và Pattern Matching
- Phần 8 30 Ngày học Rust - Day 8: Quản lý dự án với Packages, Crates và Modules
- Phần 9 30 Ngày học Rust - Day 9: Các bộ sưu tập chung (Vectors, Strings, Hash Maps)
- Phần 10 30 Ngày học Rust - Day 10: Trị dứt điểm Ác mộng Lỗi (Error Handling)
- Phần 11 30 Ngày học Rust - Day 11: Generics - Ma thuật Đa hình kiểu dữ liệu
- Phần 12 30 Ngày học Rust - Day 12: Traits - Kẻ ban phát quyền năng và Lập pháp Hành vi
- Phần 13 30 Ngày học Rust - Day 13: Vượt qua Boss cuối 'Lifetimes' - Sinh Mệnh Biến
- Phần 14 30 Ngày học Rust - Day 14: Tận diệt Bug từ trứng nước bằng Automated Tests
- Phần 15 30 Ngày học Rust - Day 15: Thực chiến Build Command Line App (CLI) đầu đời
- Phần 16 30 Ngày học Rust - Day 16: Functional Magic chốn trần gian (Closures & Iterators)
- Phần 17 30 Ngày học Rust - Day 17: Quyền năng của Smart Pointers
- Phần 18 30 Ngày học Rust - Day 18: Chinh phục Da luồng (Concurrency) - Cú đâm quyết định của Rust
- Phần 19 30 Ngày học Rust - Day 19: Tranh cãi Lập trình hướng đối tượng (OOP) trong Rust
- Phần 20 30 Ngày học Rust - Day 20: Mổ xẻ nghệ thuật Advanced Pattern Matching
- Phần 21 30 Ngày học Rust - Day 21: Sức mạnh tối thượng của Advanced Traits
- Phần 22 30 Ngày học Rust - Day 22: Về Phe Bóng Tối với Unsafe Rust
- Phần 23 30 Ngày học Rust - Day 23: Quyền năng của Đấng Tạo Hóa (Declarative Macros)
- Phần 24 30 Ngày học Rust - Day 24: Siêu Năng Lực Procedural Macros (Macro Thủ Tục)
- Phần 25 30 Ngày học Rust - Day 25: Xây dựng TCP Web Server Đa Luồng (Phần 1: Lõi Socket)
- Phần 26 30 Ngày học Rust - Day 26: Xây dựng TCP Web Server Đa Luồng (Phần 2: Bắn trả File HTML)
- Phần 27 30 Ngày học Rust - Day 27: Xây dựng TCP Web Server Đa Luồng (Phần 3: The Thread Pool)
- Phần 28 30 Ngày học Rust - Day 28: Xây dựng TCP Web Server Đa Luồng (Phần 4: Graceful Shutdown)
- Phần 29 30 Ngày học Rust - Day 29: Lên đỉnh Web Server Thực Chiến với Axum và Tokio
- Phần 30 30 Ngày học Rust - Day 30: Vượt Vọng Vàng - Đúc Kết Hành Trình Rustacean Tinh Hoa