今天帶你用 測試驅動開發(TDD) 的方式,在 Rust 裡從零打造一個命令列搜尋工具:minigrep
。
這是《Rust 程式設計語言》書中的經典範例,用來學習測試、模組化與生命週期。 Let's go 🚀
首先建立專案:
cargo new minigrep
cd minigrep
這會建立:
minigrep/
├── Cargo.toml
└── src/
└── main.rs
然後新增核心邏輯檔案:
touch src/lib.rs
TDD 第一步:寫一個失敗的測試
src/lib.rs
:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn one_result() {
let query = "duct";
let contents = "\
Rust:
safe, fast, productive.
Pick three.";
assert_eq!(vec!["safe, fast, productive."], search(query, contents));
}
}
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
vec![]
}
執行測試(預期會失敗 🔥):
cargo test

TDD 第二步:寫出讓測試通過的最小實作
修改 src/lib.rs
:
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
let mut results = Vec::new();
for line in contents.lines() {
if line.contains(query) {
results.push(line);
}
}
results
}
再次測試 💥:
cargo test

✅ 測試通過!我們的搜尋邏輯正確無誤。
現在把邏輯整合進主程式:
src/main.rs
:
use std::env;
use std::fs;
use minigrep::search;
fn main() {
// 讀取命令列參數
let args: Vec<String> = env::args().collect();
if args.len() != 3 {
eprintln!("Usage: minigrep <query> <filename>");
std::process::exit(1);
}
let query = &args[1];
let filename = &args[2];
let contents = fs::read_to_string(filename)
.expect("Should have been able to read the file");
for line in search(query, &contents) {
println!("{line}");
}
}
新增一首詩作測試檔:
echo "I'm nobody! Who are you?
Are you nobody, too?
How public, like a frog
To tell your name the livelong day
To an admiring bog!" > poem.txt
來試跑看看 🚀
搜尋 frog
:

搜尋 body
:

輸出多行,完全正確 ✅
🎯 我們剛完成了一個:
- 有測試覆蓋的核心邏輯
- 命令列工具
- 清楚生命週期管理的 Rust 專案
最棒的是——我們是用 TDD 寫出來的!
這就是 Rust TDD 的節奏:
1️⃣ 寫失敗測試
2️⃣ 實作最小可行功能 3️⃣ 確認測試通過 4️⃣ 重構並保持綠燈 💚
重複這個循環,你的程式就會又乾淨又可靠。
12️⃣
完整專案結構:
minigrep/
├── Cargo.toml
├── poem.txt
└── src/
├── lib.rs
└── main.rs
測試與主程式各司其職,
讓你的程式易於維護、擴展、重構。