နားလည်ထားရမယ့် အချက်
`#[test]` attribute ကို function တစ်ခုပေါ်တွင် ထားရင် `cargo test` က ဒီ function ကို automatically run ပြီး test ကို "pass" လို့ သတ်မှတ်ဖို့ function ဟာ panic မဖြစ်ရအောင် run ပြီးရမှာဖြစ်ပါတယ်—`assert_eq!`/`assert!` macro တွေက condition မမှန်ရင် panic ဖြစ်စေပြီး failure message ကို ဆွဲထုတ်ပေးပါတယ်။ Unit test တွေက `src/` ထဲမှာ ရေးထားလေ့ရှိပြီး (`#[cfg(test)] mod tests { ... }` ဖြင့်) private function တွေကိုပါ direct access လုပ်နိုင်ပါတယ်—function ငယ်လေးများ correct ဖြစ်ကြောင်း confirm ပါတယ်၊ integration test တွေကတော့ `tests/` directory ထဲ သီးခြားရေးပြီး public API ကိုသာ ခေါ်ကာ real usage pattern ကို simulate ပါတယ်။ Error-handling strategy ဆိုတဲ့ practical decision မှာ Lesson 11 ရဲ့ `Result<T, E>` (recoverable) နှင့် `panic!` (unrecoverable) ကို ဘယ်အချိန် ဘယ်ဟာသုံးရမလဲဆိုတာ rule of thumb ရှိပါတယ်—input ဟာ external source (user input, file, network) ကနေ လာလို့ invalid ဖြစ်နိုင်ခြေရှိရင် `Result` ကို သုံးပြီး caller ဆီ decision ပေးအပ်ရမယ်၊ ဒါပေမယ့် program ရဲ့ internal invariant ("ဒီ situation ဟာ code correct ဆိုရင် ဘယ်တော့မှ မဖြစ်သင့်ဘူး") ကို ချိုးဖောက်တာဆိုရင်တော့ `panic!` က သင့်တော်ပါတယ်—continue လုပ်ရင် data corruption ဖြစ်နိုင်ချေထက် ချက်ချင်းရပ်တန့်တာက ပိုစိတ်ချရလို့ပါ။ Library crate ရေးတဲ့အခါ `panic!` ကို minimum ထားပြီး `Result` ကို preferable ထားသင့်ပါတယ်—library ရဲ့ caller ကို ဘယ်လို error handle ချင်လဲ ဆုံးဖြတ်ခွင့် ပေးရမှာဖြစ်လို့ပါ—application binary (`main.rs`) ထဲမှာတော့ `.unwrap()`/`.expect()` ကို "program continue ရင် အန္တရာယ်ရှိတယ်" ဆိုတဲ့ situation တွေမှာ လက်တွေ့ကျကျ သုံးနိုင်ပါတယ်။
လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်
Content analyzer ရဲ့ `count_words` function အတွက် `#[test] fn counts_words_correctly() { assert_eq!(count_words("a b c"), 3); }` unit test ရေးမယ်—refactor လုပ်တိုင်း `cargo test` run ပြီး regression ကို ချက်ချင်းရှာတွေ့နိုင်ပါတယ်။ `read_lesson` function ကို `tests/read_lesson_test.rs` ထဲမှာ integration test ရေးမယ်—actual test fixture file တစ်ခုကို disk ပေါ် ဖန်တီးပြီး public API ကို end-to-end call လုပ်ကြည့်မယ်။ File path parameter ကို empty string ("") ဖြင့် ခေါ်ရင် ဒါဟာ user/caller ရဲ့ invalid input ဖြစ်နိုင်ချေရှိလို့ `Result::Err` ပြန်ပေးမယ်—ဒါပေမယ့် word count ကို accumulate နေရင်း `total` variable ရဲ့ type ကနေ overflow ဖြစ်နေရင် (theoretically ဘယ်တော့မှ ဖြစ်သင့်ခြင်းမဟုတ်တဲ့ internal invariant violation) ဆိုရင် `panic!`/`debug_assert!` ကို သုံးမယ်။
အတူတူ စမ်းရေးကြည့်မယ်
fn count_words(text: &str) -> u32 {
text.split_whitespace().count() as u32
}
fn read_lesson_body(path: &str) -> Result<String, String> {
if path.is_empty() {
return Err(String::from("path must not be empty"));
}
Ok(format!("contents of {path}"))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn counts_words_correctly() {
assert_eq!(count_words("rust ownership basics"), 3);
}
#[test]
fn rejects_empty_path() {
assert!(read_lesson_body("").is_err());
}
}`cargo test` run လိုက်ရင် "test result: ok. 2 passed" ကို terminal ထဲ ပြသနိုင်မည်။၅ မိနစ် စမ်းကြည့်
`fn classify(word_count: u32) -> &'static str` (Lesson 5 ကနေ) အတွက် `#[test]` function သုံးခု ရေးပါ—boundary value (499, 500, 1500) တစ်ခုစီအတွက် expected output ကို `assert_eq!` ဖြင့် စစ်ပါ။
သတိလေးတစ်ချက်
External input (user-provided file path, network response) ကို validate လုပ်စရာမလိုလို့ ယူဆပြီး `panic!`/`.unwrap()` ချည်းသာ သုံးခြင်း—user ရဲ့ ရိုးရိုး typo တစ်ခုကတောင် whole program ကို crash ဖြစ်စေနိုင်ပါတယ်—`Result` ဖြင့် gracefully handle သင့်ပါတယ်။
Unit test ကို private function implementation detail အတိအကျ (internal helper တစ်ခုစီ) အထိ over-test လုပ်ခြင်း—implementation ပြောင်းတိုင်း test ကျိုးနေရင် test ဟာ behavior အစား implementation ကို test လုပ်နေတာဖြစ်ပြီး refactor လုပ်ရခက်စေပါတယ်။
The Rust Programming Language — Writing Automated Tests — Rust