TL;DR
dbg!๋ก ๊ฐ๊ณผ ๋ถ๊ธฐ๋ฅผ ํ์ธํ๊ณ ์คํจํ ์ ๋ ฅ์ ์์ ํ ์คํธ๋ก ์ฌํํ๋ ๊ฐ๋ฐ ํ๋ฆcargo test์ targetยท์ด๋ฆ ํํฐยท์ถ๋ ฅ ์ต์ ์ ์ฌ์ฉํ ๋ฐ๋ณต ๊ฒ์ฆ- ์์ ํ ๋์์ ํ๊ท ํ ์คํธ๋ก ๋จ๊ธฐ๊ณ ํ์์ ๋ฐ๋ผ ๋ฌธ์ ํ ์คํธยท์๋ ์คํยทdebugger๋ก ํ์ฅ
AI-assisted
1. ์์ ํ๋ก์ ํธ ์ค๋น
์ํ ๊ฐ๊ฒฉ๊ณผ ์๋์ผ๋ก ์ต์ข ์ฃผ๋ฌธ ๊ธ์ก์ ๊ณ์ฐํ๋ CLI๋ฅผ ๋ง๋ ๋ค. ๊ณ์ฐ ๊ธฐ๋ฅ์ library์ ๋๊ณ CLI์์ ํธ์ถํ๋ค.
- ์ํ ํฉ๊ณ: ์ํ ๊ฐ๊ฒฉ์ ์๋์ ๊ณฑํ๋ค.
- ๋ฐฐ์ก๋น: ์ํ ํฉ๊ณ๊ฐ 5,000์ ๋ฏธ๋ง์ด๋ฉด 300์, 5,000์ ์ด์์ด๋ฉด ๋ฌด๋ฃ๋ค.
- ์ต์ข ๊ธ์ก: ์ํ ํฉ๊ณ์ ๋ฐฐ์ก๋น๋ฅผ ๋ํ๋ค.
ํ๋ก์ ํธ ์์ฑ
Rust์ Cargo๊ฐ ์ค์น๋ ํ๊ฒฝ์์ ์ ํ๋ก์ ํธ๋ฅผ ๋ง๋ ๋ค. ์ดํ ๋ช
๋ น์ shop_debug ๋๋ ํฐ๋ฆฌ์์ ์คํํ๋ค.
cargo new shop_debug --lib --vcs none
cd shop_debug์ด๊ธฐ ์์ ์ ํ์ผ ๊ตฌ์ฑ์ ๋ค์๊ณผ ๊ฐ๋ค. ์์ฑ๋ src/lib.rs๋ฅผ ๋ฐ๊พธ๊ณ src/main.rs๋ฅผ ์ถ๊ฐํ๋ค.
shop_debug/
โโโ Cargo.toml
โโโ src/
โโโ lib.rs
โโโ main.rssrc/lib.rs: ์ํ ํฉ๊ณ์ ๋ฐฐ์ก๋น๋ฅผ ๊ณ์ฐํ๋ ํจ์.src/main.rs: ๊ณ์ฐ ํจ์๋ฅผ ํธ์ถํ๊ณ ์ฃผ๋ฌธ ๊ธ์ก์ ์ถ๋ ฅํ๋ ์คํ ์ง์ ์ .
์ด๊ธฐ ์ฝ๋
src/lib.rs๋ฅผ ๋ค์ ์ฝ๋๋ก ๋ฐ๊พผ๋ค. ๋ฐฐ์ก๋น ์กฐ๊ฑด์ ๊ฒฝ๊ณ๊ฐ ์ค๋ฅ๊ฐ ๋ค์ด ์๋ค.
pub fn total(unit_price: u32, quantity: u32) -> u32 {
let subtotal = unit_price * quantity;
subtotal + shipping_fee(subtotal)
}
fn shipping_fee(subtotal: u32) -> u32 {
if subtotal <= 5000 { 300 } else { 0 }
}src/main.rs๋ฅผ ์ถ๊ฐํ๋ค.
fn main() {
println!("์ฃผ๋ฌธ ๊ธ์ก: {}", shop_debug::total(1000, 5));
}์คํ ๊ฒฐ๊ณผ
1,000์์ง๋ฆฌ ์ํ 5๊ฐ๋ฅผ ์ฃผ๋ฌธํ๋ค. ์ํ ํฉ๊ณ๊ฐ 5,000์์ด๋ฏ๋ก ๊ธฐ๋ํ๋ ์ต์ข ์ฃผ๋ฌธ ๊ธ์ก๋ 5,000์์ด๋ค.
cargo run --quiet์ฃผ๋ฌธ ๊ธ์ก: 5300์ปดํ์ผ์ ์ฑ๊ณตํ์ง๋ง ์ค์ ๊ธ์ก์ ๊ธฐ๋ํ ๊ธ์ก๋ณด๋ค 300์ ๋ง๋ค. ์ด ์ ๋ ฅ์ ์ฌ์ฉํด ๊ณ์ฐ ๊ณผ์ ์ ์กฐ์ฌํ๊ณ ์์ ํ ๊ฒฐ๊ณผ๋ฅผ ํ ์คํธ๋ก ๋จ๊ธด๋ค.
2. dbg๋ก ๊ณ์ฐ ๊ณผ์ ํ์ธ
์ํ ํฉ๊ณ์ ๋ฐฐ์ก๋น๋ฅผ ๋๋ ํ์ธํ๋๋ก src/lib.rs์ total()์ ๋ฐ๊พผ๋ค.
pub fn total(unit_price: u32, quantity: u32) -> u32 {
let subtotal = dbg!(unit_price * quantity);
let shipping = dbg!(shipping_fee(subtotal));
subtotal + shipping
}dbg!๋ ํํ์๊ณผ ํ๊ฐํ ๊ฐ, ์์ค ์์น๋ฅผ ์ถ๋ ฅํ๊ณ ๊ทธ ๊ฐ์ ๋ฐํํ๋ค. ์ ์ฝ๋์์๋ ํฉ๊ณ๋ฅผ ๊ณ์ฐํ๋ฉด์ ์ถ๋ ฅํ๊ณ ๋ค์ ๊ณ์ฐ์๋ ์ฌ์ฉํ๋ค.
cargo run --quiet๋ค์์ stderr์ ์ง๋จ ์ถ๋ ฅ์ด๋ค. ํ์ผ์์ ์ฝ๋์ ์์น๋ฅผ ๋ฐ๊พธ๋ฉด ์ค ๋ฒํธ๋ ๋ฌ๋ผ์ง๋ค.
[src/lib.rs:2:20] unit_price * quantity = 5000
[src/lib.rs:3:20] shipping_fee(subtotal) = 300- ์ํ ํฉ๊ณ:
unit_price * quantity๋ 5,000์ผ๋ก ๋์ ๊ณฑ์ ๊ฒฐ๊ณผ๊ฐ ๋ง๋ค. - ๋ฐฐ์ก๋น:
shipping_fee(subtotal)๋ 300์ผ๋ก ๋์ ์กฐ์ฌํ ํจ์๊ฐ ์ขํ์ก๋ค. - ์กฐ๊ฑด์:
subtotal <= 5000์๋ 5,000๋ ํฌํจ๋๋ค. ๋ฌด๋ฃ ๋ฐฐ์ก ์กฐ๊ฑด์ ๋ง์ถ๋ ค๋ฉด< 5000์ผ๋ก ๋ฐ๊ฟ์ผ ํ๋ค.
์กฐ๊ฑด ์์ฒด๋ ๋ณด๊ณ ์ถ๋ค๋ฉด ์ ์ ๋ค์์ฒ๋ผ ๊ฐ์ผ๋ค.
fn shipping_fee(subtotal: u32) -> u32 {
if dbg!(subtotal <= 5000) { 300 } else { 0 }
}์ถ๋ ฅ ์ ํ: println๊ณผ dbg
println!: ์ ํ ํ์์ผ๋ก stdout์ ์ถ๋ ฅ. CLI์ ๊ฒฐ๊ณผ ํ์ ๋ฑ์ ์ฌ์ฉ.dbg!: ์์ค ์์นยทํํ์ยท๊ฐ์ stderr์ ์ถ๋ ฅ. ๊ณ์ฐ ๊ฒฐ๊ณผ๋ ๋ถ๊ธฐ๋ฅผ ์์๋ก ํ์ธํ ๋ ์ฌ์ฉ.- ๋น๋ ์ข ๋ฅ:
dbg!๋ release ๋น๋์์๋ ์คํ. ์กฐ์ฌํ ๋ค ์์ ์ถ๋ ฅ์ ์ ๋ฆฌ.
๊ตฌ์กฐ์ฒด๋ฅผ ํ์ธํ ๋์ Debug์ ์์ ๊ถ
์ฃผ๋ฌธ ์ ๋ณด๋ฅผ ๋ฌถ์ด ํ์ธํ๋ ค๋ฉด src/main.rs๋ฅผ ๋ค์ ์ฝ๋๋ก ๋ฐ๊ฟ ์คํํ๋ค.
#[derive(Debug)]
struct Order {
unit_price: u32,
quantity: u32,
}
fn main() {
let order = Order { unit_price: 1000, quantity: 5 };
dbg!(&order);
println!("์ฃผ๋ฌธ ๊ธ์ก: {}", shop_debug::total(order.unit_price, order.quantity));
}- Debug ํ์:
#[derive(Debug)]๋ ๊ตฌ์กฐ์ฒด์ ํ๋๋ฅผ ๋๋ฒ๊น ์ฉ ํ์์ผ๋ก ์ถ๋ ฅํDebug๊ตฌํ์ ์์ฑํ๋ค. - ๋น๋ ค์ ์ถ๋ ฅ:
dbg!(&order)๋ ์ฃผ๋ฌธ์ ๋น๋ ค์ ์ถ๋ ฅํ๋ค. ์ถ๋ ฅํ ๋ค์๋order๋ฅผ ์ฌ์ฉํ๋ค. - ๊ฐ์ผ๋ก ์ ๋ฌ:
dbg!(order)์ ์ด ๊ตฌ์กฐ์ฒด๋ฅผ ๋๊ธฐ๋ฉดCopy๋ฅผ ๊ตฌํํ์ง ์์์ผ๋ฏ๋ก ์์ ๊ถ์ ๋๊ธด๋ค. ๋ฐํ๊ฐ์ ๋ฐ์ง ์์ผ๋ฉด ์ดํ ๊ฐ์ ๋ณ์๋ก ์ฃผ๋ฌธ์ ์ฌ์ฉํ์ง ๋ชปํ๋ค.
์ผ๋ฐ ์ถ๋ ฅ์์๋ Debug ํ์์ ์ฌ์ฉํ๋ค.
println!("{:?}", order); // ํ ์ค ํ์
println!("{:#?}", order); // ์ฌ๋ฌ ์ค๋ก ํผ์น ํ์3. ์คํจํ ์ฃผ๋ฌธ์ ํ ์คํธ ์ฌํ
CLI๋ก ์
๋ ฅ์ ๋ฐ๊พธ๋ฉฐ ๋งค๋ฒ ๋์ผ๋ก ํ์ธํ๋ ๋์ 5,000์ ์ฃผ๋ฌธ์ ๊ธฐ๋ ๊ฒฐ๊ณผ๋ฅผ ์ฝ๋๋ก ๋จ๊ธด๋ค. src/lib.rs์ ์๋์ ๋ค์ module์ ์ถ๊ฐํ๋ค.
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn free_shipping_at_threshold() {
let actual = total(1000, 5);
assert_eq!(actual, 5000, "5,000์ ์ฃผ๋ฌธ์ ๋ฌด๋ฃ ๋ฐฐ์ก์ด์ด์ผ ํ๋ค");
}
}ํ ์คํธ ํจ์๋ ์ ๋ ฅ์ ์ค๋นํ๊ณ ์ฝ๋๋ฅผ ํธ์ถํ ๋ค ๊ธฐ๋ ๊ฒฐ๊ณผ๋ฅผ ๊ฒ์ฌํ๋ค. ์ฌ๊ธฐ์๋ ์ค์ ์ฃผ๋ฌธ ๊ธ์ก๊ณผ 5,000์ ๋น๊ตํ๋ค.
| ๊ตฌ๋ฌธ | ์ญํ |
|---|---|
#[cfg(test)] | ํ ์คํธ ๋ชจ๋๋ก ์ปดํ์ผํ ๋ ์ด module์ ํฌํจ |
mod tests | ํ
์คํธ ์ฝ๋๋ฅผ ๋ฌถ๋ ์ผ๋ฐ module. tests๋ ๊ด๋ก์ ์ธ ์ด๋ฆ |
use super::*; | ๋ถ๋ชจ module์ ํญ๋ชฉ์ ํ์ฌ ๋ฒ์๋ก ๊ฐ์ ธ์ด |
#[test] | ํ ์คํธ ์คํ๊ธฐ๊ฐ ์คํํ ํจ์ ํ์ |
assert_eq! | ๋ ๊ฐ์ด ๊ฐ์์ง ๊ฒ์ฌํ๊ณ ๋ค๋ฅด๋ฉด panic์ผ๋ก ์คํจ ์ฒ๋ฆฌ |
cargo test --lib free_shipping_at_threshold์คํจ ์ถ๋ ฅ์์ ๋ ๊ฐ์ ๋น๊ตํ๋ค.
left: 5300
right: 5000์ด๋ ํจ์ ์์ ๋ dbg!์ ์ถ๋ ฅ๋ ์คํจ ๋ณด๊ณ ์ ํฌํจ๋๋ค. ๊ธฐ๋ ๊ฒฐ๊ณผ๋ ์ ์งํ ์ฑ ํฉ๊ณ์ ๋ฐฐ์ก๋น๋ฅผ ํ์ธํ๊ณ ์์ธ์ ๊ณ ์น๋ค.
shipping_fee()๋ฅผ ๋ค์์ผ๋ก ๋ฐ๊พผ ๋ค ๊ฐ์ ๋ช
๋ น์ ๋ค์ ์คํํ๋ค.
fn shipping_fee(subtotal: u32) -> u32 {
if subtotal < 5000 { 300 } else { 0 }
}ํ
์คํธ๊ฐ ํต๊ณผํ๋ฉด ๋ฐฐ์ก๋น ๊ธฐ์ค ์๋ยท์์ ์ฃผ๋ฌธ๋ mod tests ์์ ์ถ๊ฐํ๋ค.
#[test]
fn shipping_below_threshold() {
assert_eq!(total(1000, 3), 3300);
}
#[test]
fn free_shipping_above_threshold() {
assert_eq!(total(1000, 6), 6000);
}cargo test --lib์์ธ์ ํ์ธํ dbg!๋ ์ง์ฐ๊ณ total()์ ๋ค์ ๋จ์ํ ๊ณ์ฐ์ผ๋ก ๋ฐ๊พผ๋ค. ์ธ ํ
์คํธ๋ ๋ฐฐ์ก๋น ๊ท์น์ด ์ดํ ๋ณ๊ฒฝ์์๋ ์ ์ง๋๋์ง ํ์ธํ๋ ํ๊ท ํ
์คํธ๋ก ๋จ๊ธด๋ค.
Assertion ์ ํ: ๊ฒ์ฆํ ์กฐ๊ฑด์ ๋ง์ถค
assert!: ์กฐ๊ฑด์ดtrue์ธ์ง ๊ฒ์ฌ. ์ค๋ฅ ์ฌ๋ถ๋ ๋ฒ์ ๊ฒ์ฌ ๋ฑ์ ์ฌ์ฉ.assert_eq!: ๋ ๊ฐ์ ๊ฐ์์ ๊ฒ์ฌ. ์คํจํ๋ฉด ๋น๊ตํ ๊ฐ๋ ํ์.assert_ne!: ๋ ๊ฐ์ด ๋ค๋ฅธ์ง ๊ฒ์ฌ.- ์ถ๊ฐ ๋ฉ์์ง: assertion ๋ค์ ์คํจ ์ํฉ์ ์ค๋ช ํ๋ ํ์ ๋ฌธ์์ด ์ง์ ๊ฐ๋ฅ.
pytest ๋น๊ต: ๊ฒ์ฆ ์ฝ๋์ ํ ์คํธ ํ์
- ๊ฒ์ฆ ์ฝ๋: pytest์
assert total(1000, 5) == 5000๊ณผ Rust์assert_eq!(total(1000, 5), 5000)์ ๊ธฐ๋๊ฐ์ ๊ฒ์ฆํ๋ ์ญํ ์ด ๊ฐ์.- ํ ์คํธ ํ์: pytest๋ ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ผยทํจ์ ์ด๋ฆ ๊ท์น์ผ๋ก ์์ง. Rust๋
#[test]๋ก ํจ์๋ฅผ ํ์ํ๋ฏ๋ก ํจ์ ์ด๋ฆ์test_์ ๋์ฌ๋ ํ์๊ฐ ์๋.- ์คํจ ๋ณด๊ณ : pytest๋
assert์ ๋น๊ต๊ฐ์ ํ์ด ํ์. Rust์assert_eq!๋ ์คํจ ์ ๋ ๊ฐ์ ํ์.
4. ๊ฐ๊ฒฉ ์ ๋ ฅ ์ค๋ฅ์ ์๋ ๊ณ์ฝ ๊ฒ์ฆ
CLI์์ ๋ฐ์ ๊ฐ๊ฒฉ ๋ฌธ์์ด์ ์ซ์๋ก ๋ฐ๊พธ๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ค. ์ ์ ์ ๋ ฅ๋ฟ ์๋๋ผ ์ซ์๊ฐ ์๋ ์ ๋ ฅ๋ ํ์ธํ๋ค.
src/lib.rs์ ์ผ๋ฐ ํจ์ ๋ถ๋ถ์ ๋ค์์ผ๋ก ๋ฐ๊พผ๋ค. ์๋์ ๊ธฐ์กด mod tests๋ ์ ์งํ๋ค.
use std::num::ParseIntError;
pub fn parse_price(input: &str) -> Result<u32, ParseIntError> {
input.trim().parse()
}
pub fn total(unit_price: u32, quantity: u32) -> u32 {
assert!(quantity > 0, "quantity must be positive");
let subtotal = unit_price * quantity;
subtotal + shipping_fee(subtotal)
}
fn shipping_fee(subtotal: u32) -> u32 {
if subtotal < 5000 { 300 } else { 0 }
}- ๊ฐ๊ฒฉ ์
๋ ฅ: ์ซ์ ๋ณํ์ ์คํจํ๋ฉด
Err๋ฅผ ๋ฐํํ๋ค. ํธ์ถ์๋ ์ ๋ ฅ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๋ค. - ์๋ ๊ณ์ฝ: ์ด ๊ณ์ฐ API๋ ์ฃผ๋ฌธ ํญ๋ชฉ์ ์๋์ด ์์๋ผ๊ณ ์ ํ๋ค. ํธ์ถ์๊ฐ ๊ณ์ฝ์ ์ด๊ธฐ๋ฉด assertion์ผ๋ก panicํ๋ค.
CLI๋ ์
๋ ฅ ๋ฌธ์์ด์ ์ฌ์ฉํ๋๋ก src/main.rs๋ฅผ ๋ฐ๊พผ๋ค. ์ฒซ ๋ฒ์งธ ์ธ์๊ฐ ์์ผ๋ฉด ๊ฐ๊ฒฉ์ 1000์ผ๋ก ์ ํ๊ณ ํ์ฑ ์ค๋ฅ๋ ?๋ก ๋ฐํํ๋ค.
fn main() -> Result<(), Box<dyn std::error::Error>> {
let input = std::env::args().nth(1).unwrap_or_else(|| "1000".to_string());
let price = shop_debug::parse_price(&input)?;
println!("์ฃผ๋ฌธ ๊ธ์ก: {}", shop_debug::total(price, 5));
Ok(())
}cargo run --quiet -- ' 1000 '
cargo run --quiet -- free์ฒซ ๋ช ๋ น์ ์ฃผ๋ฌธ ๊ธ์ก 5,000์ ์ถ๋ ฅํ๊ณ ๋ ๋ฒ์งธ ๋ช ๋ น์ ๊ฐ๊ฒฉ ๋ณํ ์ค๋ฅ๋ก ์ข ๋ฃํ๋ค. ์ด ์ ๋ ฅ์ ๊ฐ๊ฐ ํ ์คํธ์ ์ฎ๊ธด๋ค.
์ ์ ๊ฒฐ๊ณผ์ Err ํ์ธ
๋ค์ ํ
์คํธ๋ฅผ ๊ธฐ์กด mod tests ์์ ์ถ๊ฐํ๋ค.
#[test]
fn parse_price_trims_spaces() {
assert_eq!(parse_price(" 1000 ").unwrap(), 1000);
}
#[test]
fn parse_price_rejects_text() {
assert!(parse_price("free").is_err());
}์ ์ ์
๋ ฅ ํ
์คํธ์ unwrap()์ ์คํจํ๋ฉด ํ
์คํธ๋ฅผ panic์ผ๋ก ๋๋ธ๋ค. ์ค๋ฅ ์
๋ ฅ ํ
์คํธ์์๋ Err๊ฐ ๋์ค๋ ๋์์ ๊ธฐ๋ํ๋ฏ๋ก is_err()๋ก ๊ฒ์ฌํ๋ค.
์ฌ๋ฌ ํจ์๊ฐ Result๋ฅผ ๋ฐํํ๋ค๋ฉด ํ
์คํธ ํจ์๋ Result๋ฅผ ๋ฐํํ๊ณ ?๋ฅผ ์ฌ์ฉํ๋ค.
#[test]
fn parsed_price_calculates_total() -> Result<(), Box<dyn std::error::Error>> {
let price = parse_price("1000")?;
assert_eq!(total(price, 5), 5000);
Ok(())
}- ์ฑ๊ณต ๋ฐํ:
Ok(())๋ฅผ ๋ฐํํ๋ ๊ฒฝ๋ก๋ค. ์์ assertion๋ ํต๊ณผํด์ผ ํ๋ค. Err๋ฐํ:?๊ฐ ์ค๋ฅ๋ฅผ ๋ฐํํ๋ฉด ํ ์คํธ๊ฐ ์คํจํ๋ค.Box<dyn std::error::Error>: ์ฌ๋ฌ ์ข ๋ฅ์ ์ค๋ฅ๋ฅผ ๋ฐํํ ๋ ์ฐ๋ ํํ๋ค. ์ด ์์ ์ฒ๋ผ ํ์ฑ ์ค๋ฅ๋ง ์์ผ๋ฉด ๋ฐํ ํ์ ์Result<(), ParseIntError>๋ก ์ขํ๋ ๋๋ค.
์์ํ panic ํ์ธ
์๋ ๊ณ์ฝ๋ ํ ์คํธ๋ก ๋จ๊ธด๋ค.
#[test]
#[should_panic(expected = "quantity must be positive")]
fn zero_quantity_panics() {
total(1000, 0);
}#[should_panic]์ ํจ์๊ฐ panicํด์ผ ํต๊ณผํ๋ค. expected๋ฅผ ์ง์ ํ๋ฉด panic ๋ฉ์์ง์ ์ด ๋ฌธ์์ด์ด ํฌํจ๋์ด์ผ ํ๋ฏ๋ก ๋ค๋ฅธ ์์ธ์ panic์ผ๋ก ํต๊ณผํ๋ ๋ฒ์๋ฅผ ์ค์ธ๋ค.
cargo test --lib์ด ๋จ๊ณ์์๋ ๋ฐฐ์ก๋น ํ ์คํธ ์ธ ๊ฐ์ ํ์ฑยท์๋ ํ ์คํธ ๋ค ๊ฐ๋ฅผ ํฉ์ณ ์ผ๊ณฑ ๊ฐ๊ฐ ํต๊ณผํ๋ค.
ํ ์คํธ ๋ฐํ๊ฐ: Result์ should_panic
Resultํ ์คํธ:Ok(())๋ฅผ ๋ฐํํ๋ฉด ํต๊ณผํ๊ณErr๋ฅผ ๋ฐํํ๋ฉด ์คํจ.#[should_panic]ํ ์คํธ: ๋ฐํ ํ์ ์ด()์ธ ํจ์์ ์ ์ฉ.Result๋ฐํ ํ ์คํธ์ ๋ฐ๋ก ์์ฑ.- ๋ช ์ธ: ๋ฐํ๊ฐ๊ณผ panic ํ์ ์ ์ธ๋ถ ๊ท์น์ ํ ์คํธ attribute ์ฐธ๊ณ .
pytest ๋น๊ต: ์์ ์์ธ์ panic ๊ฒ์ฆ
- ์์ ์คํจ: pytest๋ pytest.raises()๋ก ์ง์ ํ ์์ธ ๋ฐ์์ ๊ฒ์ฆ. Rust๋
#[should_panic]์ผ๋ก ํ ์คํธ ํจ์์ panic์ ๊ฒ์ฆ.- ๋ฉ์์ง ์กฐ๊ฑด:
pytest.raises(..., match=...)๋ ์ ๊ท์์ผ๋ก ๋น๊ต.#[should_panic(expected = "...")]๋ ๋ฌธ์์ด ํฌํจ ์ฌ๋ถ๋ก ๋น๊ต.- ์ค๋ฅ ๋ฐํ: Rust์
Result::Err๋ ๋ฐํ๊ฐ์ด๋ฏ๋ก assertion์ผ๋ก ํ์ธ. ์ด ์์ ์parse_price_rejects_text()๋is_err()๋ก ๊ฒ์ฌ.
5. ํ ์คํธ ์ ํ ์คํ๊ณผ ์ถ๋ ฅ ํ์ธ
๊ฐ๋ฐ ์ค์๋ ์์ ์ค์ธ ํจ์์ ํ ์คํธ๋ฅผ ๋จผ์ ์คํํ๋ค. ํ ์คํธ ์คํ ์ต์ ์ผ๋ก ์ด๋ฆ๊ณผ ์คํ ๋ฒ์๋ฅผ ์ขํ๋ค.
Target๊ณผ ์ด๋ฆ ํํฐ
# package์ ๊ธฐ๋ณธ ํ
์คํธ ๋์ ์คํ
cargo test
# library์ unit test์์ ์ด๋ฆ์ parse_price๊ฐ ํฌํจ๋ ํ
์คํธ ์คํ
cargo test --lib parse_price
# library์ unit test ํ๋๋ฅผ ์ ์ฒด ์ด๋ฆ์ผ๋ก ์ง์
cargo test --lib tests::free_shipping_at_threshold -- --exact
# ํ
์คํธ ์ด๋ฆ๊ณผ ๋ชฉ๋ก ํ์ธ
cargo test --lib -- --list- ๋ถ๋ถ ์ด๋ฆ: ๊ธฐ๋ณธ ์ด๋ฆ ํํฐ๋ ๋ถ๋ถ ๋ฌธ์์ด์ ๋น๊ตํ๋ค.
parse_price๋ ๋ ํ์ฑ ํ ์คํธ์ ํด๋นํ๋ค. - ์ ์ฒด ์ด๋ฆ:
--exact์์๋ module ๊ฒฝ๋ก๊น์ง ๋น๊ตํ๋ค. ์ฌ๊ธฐ์๋tests::free_shipping_at_threshold๊ฐ ์ ์ฒด ์ด๋ฆ์ด๋ค. - Target:
--lib๋ library์ unit test๋ฅผ ์ ํํ๋ค. binary์ unit test๋ ๋ณ๋ ๋์์ด๋ค.
| ์ธ์ ์์น | ์ฒ๋ฆฌํ๋ ๋์ | ์ |
|---|---|---|
-- ์์ Cargo ์ต์
| ๋น๋ํ packageยทtarget ๋ฑ์ ์ ํ | --lib, --release |
-- ์์ ์ด๋ฆ ํํฐ | Cargo๊ฐ ํ ์คํธ ์คํ๊ธฐ๋ก ์ ๋ฌ | parse_price |
-- ๋ค์ ์ต์
| ํ ์คํธ ์คํ๊ธฐ๊ฐ ์คํ ๋ฐฉ๋ฒ์ ์กฐ์ | --exact, --nocapture |
ํต๊ณผํ ํ ์คํธ์ ์ถ๋ ฅ ํ์ธ
ํ ์คํธ ์์์ ๊ฐ์ด ๊ถ๊ธํ๋ฉด ์ ์ ๋ค์์ฒ๋ผ ๋ฐ๊พผ๋ค.
#[test]
fn free_shipping_at_threshold() {
let actual = dbg!(total(1000, 5));
assert_eq!(actual, 5000);
}# ์ถ๋ ฅ ์บก์ฒ๋ฅผ ๋๊ณ ์คํ ์ค ์ถ๋ ฅ ํ์ธ
cargo test --lib free_shipping_at_threshold -- --nocapture
# ์บก์ฒ๋ ์ ์งํ๊ณ ํต๊ณผํ ํ
์คํธ์ ์ถ๋ ฅ๋ ์คํ ํ ํ์
cargo test --lib free_shipping_at_threshold -- --show-output- ๊ธฐ๋ณธ ์คํ: ์ฑ๊ณตํ ํ ์คํธ์ ์ถ๋ ฅ์ ์จ๊ธฐ๊ณ ์คํจํ ํ ์คํธ๋ ์บก์ฒํ ์ถ๋ ฅ๋ ๋ณด๊ณ ํ๋ค.
--nocapture: ์ถ๋ ฅ์ ๋ฐ๋ก ๋ด๋ณด๋ธ๋ค. ์ฌ๋ฌ ํ ์คํธ๊ฐ ๋ณ๋ ฌ๋ก ์คํ๋๋ฉด ์ถ๋ ฅ์ด ์์ผ ์ ์๋ค.--show-output: ์บก์ฒํ ์ฑ๊ณต ์ถ๋ ฅ๋ ๊ฒฐ๊ณผ์ ํฌํจํ๋ค. ํ ์คํธ๋ณ ์ถ๋ ฅ์ ๋ชจ์์ ์ฝ์ ๋ ์ฌ์ฉํ๋ค.
์ค๋ ๊ฑธ๋ฆฌ๋ ํ ์คํธ์ ๊ณต์ ์ํ
์ธ๋ถ ์๋น์ค๋ ๋ง์ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ ํ
์คํธ๋ #[ignore = "์ด์ "]๋ก ๊ธฐ๋ณธ ์คํ์์ ์ ์ธํ ์ ์๋ค. Ignore๋ ํ
์คํธ๋ ์ปดํ์ผ์ ํ๋ค.
# ignore ํ์๊ฐ ๋ถ์ ํ
์คํธ๋ง ์คํ
cargo test -- --ignored
# ignore๋ ํ
์คํธ๋ ํฌํจํด ์คํ
cargo test -- --include-ignored
# ์ด๋ฆ์ slow๊ฐ ํฌํจ๋ ํ
์คํธ ์ ์ธ
cargo test -- --skip slow
# ํ
์คํธ ํจ์๋ฅผ ํ ๋ฒ์ ํ๋์ฉ ์คํ
cargo test -- --test-threads=1๊ณต์ ์ํ: ํ ์คํธ์ ์คํ ์์์ ์์กดํ์ง ์๊ธฐ
- ๊ธฐ๋ณธ ์คํ: ๊ฐ์ ํ ์คํธ ์คํ ํ์ผ์ ํจ์๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ณ๋ ฌ ์คํ.
- ์ถฉ๋ ์ฌ๋ก: ๊ฐ์ ํ์ผ์ ๋ฎ์ด์ฐ๊ฑฐ๋ ํ๊ฒฝ ๋ณ์ยท์ ์ญ ์ํ๋ฅผ ๊ณต์ ํ๋ฉด ์๋ก ์ํฅ์ ์ค ์ ์์.
- ์กฐ์ฌ ๋ฐฉ๋ฒ: ์์ฐจ ์คํ์ผ๋ก ์ฆ์ ๋ณํ๋ฅผ ํ์ธํ ๋ค ํ ์คํธ๋ณ ๋ฐ์ดํฐ๋ ์์์ ๋ถ๋ฆฌ.
- ์์: ์์ฐจ ์คํ ์ต์ ๋ ํน์ ํ ์คํธ๊ฐ ๋จผ์ ์คํ๋๋ค๋ ์์กด ๊ด๊ณ๋ฅผ ๋ณด์ฅํ๋ ์๋จ์ ์๋.
pytest ๋น๊ต: ํ ์คํธ ์ ํ๊ณผ ์ถ๋ ฅ ์บก์ฒ
- ์ด๋ฆ ์ ํ: pytest์ -k์ Rust์ ์ด๋ฆ ํํฐ๋ ๊ด์ฌ ์๋ ํ ์คํธ๋ง ๊ณจ๋ผ ์คํ.
-k๋andยทorยทnot์ ์กฐํฉํ๋ฉฐ Rust์ ๊ธฐ๋ณธ ์ด๋ฆ ํํฐ๋ ๋ถ๋ถ ๋ฌธ์์ด์ ๋น๊ต.- ์ถ๋ ฅ ๊ด์ฐฐ: pytest์ -s์ Rust์
--nocapture๋ ์บก์ฒ๋ฅผ ๊บผ ์คํ ์ค ์ถ๋ ฅ์ ํ์ธํ๋ ์ต์ .- ์ ์ฒด ์ด๋ฆ: pytest๋ ํ์ผ ๊ฒฝ๋ก์
::ํจ์๋ช์ผ๋ก ์คํํ ํ ์คํธ๋ฅผ ์ง์ . Rust ์์ ๋tests::free_shipping_at_threshold๊ฐ์ ์ ์ฒด ์ด๋ฆ๊ณผ--exact๋ฅผ ์ฌ์ฉ.
6. ๊ณต๊ฐ API์ ๋ฌธ์ ์์ ๊ฒ์ฆ
์ง๊ธ๊น์ง ์์ฑํ ์ฝ๋๋ unit test๋ค. ๊ฐ๊ฒฉ ๊ณ์ฐ ํจ์๋ฅผ library ๋ฐ์์ ์ฌ์ฉํ๋ ๋ชจ์ต๊ณผ ๋ฌธ์์ ์ ์ ์ฌ์ฉ๋ฒ๋ ๊ฒ์ฌํ๋ค.
| ์ข ๋ฅ | ๊ธฐ๋ณธ ์์น | ๊ฒ์ฆํ ๋ด์ฉ |
|---|---|---|
| Unit test | ์์ค ๋ด๋ถ์ #[cfg(test)] mod tests | ์์ ํจ์์ ๋ด๋ถ ๊ตฌํ |
| Integration test | tests/*.rs | ์ธ๋ถ crate ๊ด์ ์ ๊ณต๊ฐ API |
| Doc test | /// ๋ฌธ์ ์ฃผ์ ์์ Rust ์์ | API ๋ฌธ์์ ์ฌ์ฉ ์ฝ๋ |
๊ฐ์ module์ ๋ด๋ถ ๊ตฌํ ๊ฒ์ฌ
private ํจ์๊ฐ ๋ณต์กํด์ก๋ค๋ฉด mod tests์ ๋ค์ ํ
์คํธ๋ ์ถ๊ฐํ๋ค.
#[test]
fn shipping_fee_at_threshold() {
assert_eq!(shipping_fee(5000), 0);
}์์์ธ tests module์์๋ ๋ถ๋ชจ module์ private ํญ๋ชฉ์ ์ฌ์ฉํ๋ค. use super::*;๋ ์ด ์ด๋ฆ์ ๊ฐ์ ธ์ค๋ ๊ตฌ๋ฌธ์ด๋ค.
Integration test์์ ๊ณต๊ฐ API ํธ์ถ
tests ๋๋ ํฐ๋ฆฌ๋ฅผ ๋ง๋ ๋ค.
mkdir -p teststests/api.rs์ ๋ค์์ ๋ฃ๋๋ค.
use shop_debug::{parse_price, total};
#[test]
fn entered_price_produces_order_total() {
let price = parse_price(" 1000 ").unwrap();
assert_eq!(total(price, 5), 5000);
}
#[test]
fn small_order_includes_shipping() {
assert_eq!(total(1000, 3), 3300);
}Integration test๋ ๋ณ๋ crate๋ก ์ปดํ์ผํด library๋ฅผ ์ฌ์ฉํ๋ค. ์ธ๋ถ์์ ํธ์ถํ ๊ณต๊ฐ API์ธ parse_price์ total์ ๊ฐ์ ธ์จ๋ค.
cargo test --test apiDoc test๋ก ์ฌ์ฉ๋ฒ ํ์ธ
src/lib.rs์ total() ๋ฐ๋ก ์์ ๋ค์ ๋ฌธ์ ์ฃผ์์ ๋ถ์ธ๋ค.
/// ์ํ ๊ธ์ก๊ณผ ๋ฐฐ์ก๋น๋ฅผ ํฉ์ฐํ๋ค. ์๋์ ์์์ฌ์ผ ํ๋ค.
///
/// # Examples
///
/// ```
/// assert_eq!(shop_debug::total(1000, 3), 3300);
/// assert_eq!(shop_debug::total(1000, 5), 5000);
/// ```๋ฌธ์ ํ ์คํธ๋ ๋ฌธ์์ Rust ์์ ๋ฅผ ์ปดํ์ผํ๊ณ ์คํํ๋ค. API๋ฅผ ๋ฐ๊ฟจ์ ๋ ๋ฌธ์์ ์ฌ์ฉ๋ฒ๋ ํจ๊ป ํ์ธํ๋ค.
# library์ ๋ฌธ์ ํ
์คํธ๋ง ์คํ
cargo test --doc
# ๊ธฐ๋ณธ ๋์์ unitยทintegrationยทdoc test ์คํ
cargo testpytest ๋น๊ต: ํ ์คํธ ๋ฐฐ์น์ ๋ฌธ์ ์์
- ํ์ผ ๋ฐฐ์น: pytest์์๋ ํ ์คํธ ํ์ผ์
tests/test_pricing.py์ฒ๋ผ ๋ฐฐ์นํ๊ณ ํจ์๋ฅผ importํด ํ ์คํธ. Rust์ ์์ค ๋ด๋ถ unit test๋ private ํญ๋ชฉ์ ์ ๊ทผํ๋ฉฐ root์tests/๋ ๋ณ๋ crate๋ก ์ปดํ์ผํด ๊ณต๊ฐ API๋ฅผ ์ฌ์ฉ.- ๊ฒ์ฆ ๋ฒ์: pytest๋ ์์ ํจ์๋ ์ฌ๋ฌ ๊ธฐ๋ฅ์ ์ฐ๋์ ๊ฐ์ ์์งยท์คํ ๋ฐฉ์์ผ๋ก ๊ฒ์ฌ. Rust๋ unitยทintegration test์ crate ๊ฒฝ๊ณ๋ฅผ ๊ตฌ๋ถ.
- ๋ฌธ์ ์์ : pytest์
--doctest-modules๋ module์ docstring ์์ ๋ฅผ ์์ง. Rust doc test๋ library ๋ฌธ์์ Rust ์์ ๋ฅผ ์ปดํ์ผํ๊ณ ์คํ.
7. ์ ์ฅ ์ ํ ์คํธ ์๋ ์คํ
์ ํจ์๋ฅผ ์์ฑํ๋ค ๋์์ด ๊ถ๊ธํด์ง๋ฉด ๊ฐ์ ํ์ผ์ mod tests์ ์
๋ ฅ์ ํ๋ ๋ฃ๋๋ค. ํ์ํ ๊ฐ์ dbg!๋ฅผ ๋ถ์ด๊ณ ์ด ํ
์คํธ๋ง ๋ฐ๋ณตํด์ ์คํํ๋ค.
cargo test --lib parsed_price_calculates_total -- --nocapture๋ฐ๋ณตํ๋ ๋ช ๋ น์ ์ ์ฅํ ๋ ์๋ ์คํํ๋๋ก ์ค์ ํ๋ค. Bacon์ ๋ณ๋ ํฐ๋ฏธ๋์ ์ผ๋๋ฉด ์ฝ๋ ๋ณ๊ฒฝ์ ๊ฐ์งํด ๊ฒ์ฌยทํ ์คํธ๋ฅผ ๋ค์ ์คํํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ํ์ํ๋ค.
cargo install --locked bacon
bacon test- ํ๋ฉด ๊ตฌ์ฑ: ํ์ชฝ์๋ ์๋ํฐ, ๋ค๋ฅธ ์ชฝ์๋ Bacon์ ๋๋ค.
- ์คํจ ์ง์ค: Bacon์์ ํ
์คํธ ์คํจ ํ
f๋ฅผ ๋๋ฅด๋ฉด ์คํจํ ํ ์คํธ์ ์ง์คํ๋ค.Esc๋ก ์ ์ฒด ํ ์คํธ๋ก ๋์๊ฐ๋ค. - ์์ ์ ํ: ๊ธฐ๋ณธ ํ ์คํธ job ์ธ์ ํน์ targetยทํจ์๋ง ์คํํ job์ ์ง์ ํ๋ค.
์์ ํ
์คํธ๋ง ๋ฐ๋ณตํ๋ ค๋ฉด ํ๋ก์ ํธ root์ bacon.toml์ ๋ค์ job๊ณผ ํค ์ค์ ์ ์ถ๊ฐํ๋ค. ํ์ผ์ด ์์ผ๋ฉด ์๋ก ๋ง๋ ๋ค.
[jobs.price]
command = ["cargo", "test", "--lib", "parsed_price_calculates_total", "--", "--nocapture"]
need_stdout = true
[keybindings]
ctrl-r = "toggle-raw-output"bacon price์ด์ ๊ฐ๊ฒฉ ํ์ฑ์ด๋ ๊ณ์ฐ ํจ์๋ฅผ ์์ ํ๊ณ ์ ์ฅํ๋ฉด ๊ฐ์ ํ
์คํธ๊ฐ ๋ค์ ์คํ๋๋ค. Ctrl+R๋ก ์๋ณธ ์ถ๋ ฅ์ ํ์ํ๋ฉด ํต๊ณผํ ํ
์คํธ์ dbg! ์ถ๋ ฅ๋ ํ์ธํ๋ค. ์คํ ์๊ฐ์ ํ๋ก์ ํธ ๊ท๋ชจยท๋ณ๊ฒฝ ๋ฒ์ยท๋น๋ ์บ์์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ค.
๊ธฐ์กด ๋๊ตฌ: cargo-watch์ ์๋ ์คํ
- ์ญํ : ํ์ผ ๋ณ๊ฒฝ์ ๊ฐ์งํด ์ง์ ํ Cargo ๋ช ๋ น์ ๋ค์ ์คํ.
- ์ ์ง๋ณด์: cargo-watch ์ ์ฅ์๋ archive ์ํ์ด๋ฉฐ ์์ฑ์๋ Bacon์ด๋ Watchexec๋ฅผ ๊ถ์ฅ.
- ๊ธฐ์กด ํ๊ฒฝ: ์ด๋ฏธ ์ค์นํด ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ๋ค์ ๋ช ๋ น์ผ๋ก ๊ฐ์ ํ ์คํธ๋ฅผ ๋ฐ๋ณต ์คํ.
cargo watch -x 'test --lib parsed_price_calculates_total -- --nocapture'ํ๊ท ํ ์คํธ์ ์์ ์ถ๋ ฅ ์ ๋ฆฌ
- ๊ถ๊ธํ ๋์์ ์์ ํ ์คํธ๋ก ํธ์ถํ๋ค.
dbg!์ถ๋ ฅ์ผ๋ก ์ ๋ ฅยท์ค๊ฐ ๊ฐยท๋ถ๊ธฐ๋ฅผ ํ์ธํ๋ค.- ๊ธฐ๋ํ ๋์์ assertion์ผ๋ก ์์ฑํ๋ค.
- ๊ตฌํ์ ๊ณ ์น๊ณ ํ ์คํธ๊ฐ ํต๊ณผํ๋์ง ํ์ธํ๋ค.
dbg!๋ฅผ ์ง์ฐ๊ณ ์ฌํ ํ ์คํธ๋ฅผ ๋จ๊ธด๋ค.
๋จ์ ์์ ์ถ๋ ฅ์ Clippy์ dbg_macro ๊ฒ์ฌ๋ก ์ฐพ๋๋ค.
cargo clippy --all-targets -- -W clippy::dbg_macro--all-targets๋ก ํ
์คํธ ๋์๋ ๊ฒ์ฌํ๋ค. src/lib.rs ๋งจ ์์ ๋ค์ ์์ฑ์ ๋๋ฉด ์ด crate์์ ํญ์ ๊ฒฝ๊ณ ํ๋๋ก ์ค์ ํ๋ค.
#![warn(clippy::dbg_macro)]pytest ๋น๊ต: ์ ์ฅ ์ ํ ์คํธ ์ฌ์คํ
- ์๋ ์คํ: pytest ํ๊ฒฝ์ pytest-watcher์ฒ๋ผ Baconยทcargo-watch๋ ํ์ผ ๋ณ๊ฒฝ์ ๊ฐ์งํด ํ ์คํธ ๋ช ๋ น์ ์ฌ์คํ.
- ์ฌํ ์ฌ๋ก: ์์ชฝ ๋ชจ๋ ์กฐ์ฌํ ์ ๋ ฅ์ ์์ ํ ์คํธ๋ก ๊ณ ์ ํ๊ณ ์์ ํ ๊ฐ์ ๊ธฐ๋๊ฐ์ ๋ค์ ๊ฒ์ฆ.
- ์ปดํ์ผ ๋จ๊ณ: Rust๋ ๋ณ๊ฒฝํ ์ฝ๋๋ฅผ ์ปดํ์ผํ ๋ค ํ ์คํธ ์คํ ํ์ผ์ ์คํ.
8. panic ํธ์ถ ๊ฒฝ๋ก์ ์คํ ์ํ ํ์ธ
์ฌ๋ฌ ํจ์๋ฅผ ๊ฑฐ์น ๋ค panicํ๋ค๋ฉด backtrace๋ฅผ ์ผ ํธ์ถ ๊ฒฝ๋ก๋ฅผ ํ์ธํ๋ค. ์๋์ด 0์ธ ์ฃผ๋ฌธ์ total()์ assertion์์ panicํ๋ฏ๋ก ์์ ํ
์คํธ๋ก ์ถ๋ ฅ ๋ฐฉ์์ ํ์ธํ๋ค.
RUST_BACKTRACE=1 cargo test --lib zero_quantity_panics -- --nocapture- panic ๋ฉ์์ง:
quantity must be positive์ assertion ์์น๋ฅผ ํ์ธํ๋ค. - ํธ์ถ ๊ฒฝ๋ก: ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ panic ์ฒ๋ฆฌ ๋ถ๋ถ์ ์ง๋
shop_debug::total๊ณผtests::zero_quantity_panics๊ฐ์ ์ง์ ์์ฑํ ํจ์๋ฅผ ์ฐพ๋๋ค. - ํ
์คํธ ๊ฒฐ๊ณผ: ์ด ํ
์คํธ๋
#[should_panic]์ผ๋ก ์์ํ panic์ ๊ฒ์ฆํ๋ฏ๋ก ํต๊ณผํ๋ค. panic ๋ฉ์์ง ์ถ๋ ฅ๊ณผ ํ ์คํธ ์คํจ๋ ๊ตฌ๋ถํด์ ์ฝ๋๋ค.
์ค์ ์กฐ์ฌ์์๋ ๋ฌธ์ ๋ฅผ ์ผ์ผํจ ์คํ ๋ช ๋ น์ด๋ ํ ์คํธ์ ๊ฐ์ ํ๊ฒฝ ๋ณ์๋ฅผ ๋ถ์ธ๋ค. Backtrace๋ ํธ์ถ ๊ฒฝ๋ก๋ฅผ ๋ณด์ฌ์ฃผ๋ฉฐ ๊ฐ ํจ์์ ๋ชจ๋ ๋ณ์ ๊ฐ์ ์ ์ฅํ๋ ๊ธฐ๋ฅ์ ์๋๋ค.
Debugger์ breakpoint์ ์ํ ํ์ธ
๋ฐ๋ณต๋ฌธ์ด๋ ์ฌ๋ฌ ํจ์์ ์ํ๋ฅผ ํจ๊ป ๋ด์ผ ํ๋ค๋ฉด breakpoint์์ ์คํ์ ๋ฉ์ถ๋ค. macOS์์ LLDB๋ฅผ ์ฌ์ฉํ ์ ์๋ ํ๊ฒฝ์์๋ ๋จผ์ ์คํ ํ์ผ์ ๋น๋ํ๋ค.
cargo build
rust-lldb target/debug/shop_debugrust-lldb๋ Rust ๋๊ตฌ์ฒด์ธ์์ ์ ๊ณตํ๋ LLDB ์คํ wrapper๋ค. LLDB๊ฐ ์ค์น๋ ํ๊ฒฝ์์ LLDB ๋ช
๋ น์ผ๋ก ํจ์์ breakpoint๋ฅผ ์ค์ ํ๊ณ ์คํํ๋ค.
breakpoint set --name shop_debug::total
run
frame variable
next
thread backtrace
continue
quit| ๋ช ๋ น | ํ์ธํ๋ ๋ด์ฉ |
|---|---|
breakpoint set --name ... | ์ด ํจ์์์ ๋ฉ์ถ๋๋ก ์์น ์ง์ |
run | ํ๋ก๊ทธ๋จ ์คํ |
frame variable | ํ์ฌ stack frame์ ๋ณ์ ํ์ธ |
next | ํจ์ ํธ์ถ ์์ผ๋ก ๋ค์ด๊ฐ์ง ์๊ณ ๋ค์ ์์ค ์ค๋ก ์ด๋ |
step | ํธ์ถํ ํจ์ ์์ผ๋ก ์ง์ ํ๋ฉฐ ํ ์ค์ฉ ์คํ |
thread backtrace | ํ์ฌ thread์ ํธ์ถ ์คํ ํ์ธ |
continue | ๋ค์ breakpoint๋ ์ข ๋ฃ๊น์ง ๊ณ์ ์คํ |
total()์์ ๋ฉ์ท๋ค๋ฉด ์ธ์๋ก ๋ฐ์ unit_price์ quantity๋ฅผ ํ์ธํ๋ค. ๊ณ์ฐ ์ค์ ์ง๋ ๋ค์๋ subtotal๋ ํ์ธํ๊ณ ๊ฐ์ด ์์๊ณผ ๋ฌ๋ผ์ง๋ ์์น๋ฅผ ์ฐพ๋๋ค.
๋น๋ ์ค์ : release์์๋ ๊ฐ์ ๋์์ธ์ง ํ์ธ
- ์ต์ ํ: ์ต์ ํํ ์คํ ํ์ผ์์๋ ์์ค ์ค๊ณผ ์คํ ์์๊ฐ ๋ฌ๋ผ์ง๊ฑฐ๋ ์ผ๋ถ ๋ณ์๊ฐ ๋ณด์ด์ง ์์ ์ ์์.
- Debug ์ ๋ณด: ๋ณ์ยท์์ค ์์น ์กฐ์ฌ์ ํ์ํ ์ ๋ณด๋ Cargo profile์์ ์ค์ .
- ์ ์ overflow:
overflow-checks๋ฅผ ์ผ๋ฉด overflow์์ panic. ๊ธฐ๋ณธ devยทtest์ release์ ์ค์ ์ด ๋ฌ๋ผ ์คํ ๊ฒฐ๊ณผ๋ฅผ ๋น๊ตํ ๋ ํ์ธ.- ๋น๋์ ๋ ๋ฆฝ์ ์ธ ๊ณ์ฝ: ์์ ์
assert!(quantity > 0, ...)๋ release์์๋ ์คํ.debug_assert!๋ ๊ธฐ๋ณธ release ์ค์ ์์ ๊ฒ์ฌํ์ง ์์.
release ํ ์คํธ๋ ํ์ธํ๋ค.
cargo test --releasepytest ๋น๊ต: ์คํจ ๊ฒฝ๋ก์ ์คํ ์ํ ์กฐ์ฌ
- ์คํจ ๊ฒฝ๋ก: pytest๋ ์คํจ ๋ณด๊ณ ์ traceback์ ํ์. Rust์ panic์
RUST_BACKTRACE=1๋ก ํธ์ถ ์คํ ํ์ธ.- ์ค๋จ ์กฐ์ฌ: pytest์
--pdb๋ ์คํจ ์ pdb์ ์ง์ . Rust ์์ ๋ ๋ณ๋ debugger์ธ LLDB๋ก ์คํ ํ์ผ์ ์กฐ์ฌ.- ์คํ ๋์: pytest๋ Python ์ฝ๋๋ฅผ ์คํํ๋ฉฐ LLDB๋ ์ปดํ์ผํ Rust ์คํ ํ์ผ์ ์ฌ์ฉ. ์์ค๋ฅผ ์์ ํ๋ฉด ๋ค์ ๋น๋.
9. ํ ์คํธ ๋์๊ณผ ํ์ผ ๊ตฌ์ฑ
๊ฐ๋ฐ ์ค์๋ ์์ ํ ํจ์์ ํ ์คํธ๋ฅผ ๋จผ์ ์คํํ๊ณ ๋ณ๊ฒฝ์ ๋ง๋ฌด๋ฆฌํ ๋ ์ ์ฒด ํ ์คํธ๋ฅผ ์คํํ๋ค. ์ด๋ฆ ํํฐ๋ ์คํํ ํจ์๋ฅผ ์ค์ด๊ณ target ์ ํ์ ๋น๋ํ ๋ฒ์๋ ์ค์ด๋ ์ญํ ์ ํ๋ค.
๊ณ์ฐ ๋ก์ง๊ณผ CLI๋ฅผ ๋ถ๋ฆฌํ๋ ์ด์
ํ์ฌ src/lib.rs์ ๊ณ์ฐยทํ์ฑ ๊ธฐ๋ฅ์ unit test๋ก ํธ์ถํ๊ฑฐ๋ integration test์์ importํ๋ค. src/main.rs๋ library๋ฅผ ํธ์ถํด ์ถ๋ ฅํ๋ ์ญํ ์ ๋งก๋๋ค.
- Library์ unit test: ๊ฐ๊ฒฉ ๊ณ์ฐยทํ์ฑ ๊ท์น์ ์์ ์ ๋ ฅ์ผ๋ก ํ์ธํ๋ค.
- Library์ integration test: ์ฌ์ฉ์๊ฐ ํธ์ถํ๋ ๊ณต๊ฐ API ๊ฒฝ๊ณ๋ฅผ ๊ฒ์ฌํ๋ค.
- CLI์ integration test: ํ์ํ๋ฉด ์คํ ํ์ผ์ ๋ณ๋ ํ๋ก์ธ์ค๋ก ์คํํด ์ถ๋ ฅยท์ข ๋ฃ ์ํ๋ฅผ ๊ฒ์ฌํ๋ค.
Binary crate: main.rs์๋ unit test ์์ฑ ๊ฐ๋ฅ
- ๊ฐ์ crate์ ํ ์คํธ:
main.rs๋ ๊ทธ ํ์ module์๋#[cfg(test)] mod tests๋ฅผ ๋ฐฐ์น.- Library ๋ถ๋ฆฌ์ ์ด์ : ๊ณต๊ฐ Rust API๋ฅผ ๋ค๋ฅธ crate์์ importํ๊ณ ์ฌ๋ฌ binary์์ ๊ณต์ ํ๊ธฐ ์ฌ์์ง.
- CLI ์คํ: binary๋ฅผ library์ฒ๋ผ importํ๋ ๋์ ์คํ ํ์ผ์ ํธ์ถํ๋ integration test๋ ๊ฐ๋ฅ.
Integration test target ํตํฉ
๊ธฐ๋ณธ Cargo ๊ตฌ์กฐ์์๋ tests/api.rs, tests/parsing.rs๊ฐ ๊ฐ๊ฐ ๋ณ๋ ์คํ ํ์ผ์ด ๋๋ค. ํ์ผ์ด ๋ง์์ ธ ๋น๋ยท๋งํฌ ๋น์ฉ์ด ์ปค์ก๋ค๋ฉด ํ๋์ target ์๋์ module๋ก ๋ฌถ๋ ๊ตฌ์ฑ์ ๊ฒํ ํ๋ค.
์๋ฅผ ๋ค์ด api.rs์ parsing.rs๊ฐ ์๊ธด ํ๋ก์ ํธ๋ฅผ ๋ค์์ฒ๋ผ ๋๋๋ค. ์ด ๊ธ์ ์์ ์์ ์์๋ ๊ธฐ์กด tests/api.rs๋ฅผ ์ ์งํด๋ ์ถฉ๋ถํ๋ค.
tests/
โโโ it/
โโโ main.rs
โโโ api.rs
โโโ parsing.rstests/it/main.rs๋ ๋ค์ module์ ์ฐ๊ฒฐํ๋ค.
mod api;
mod parsing;๋ณ๋ crate์ ์๋ฅผ ์ค์ด๊ณ ๊ฐ module์ ํ ์คํธ๋ ๊ฐ์ ์คํ ํ์ผ์์ ์คํํ๋ค. ํจ์๋ ์ฌ์ ํ ์ด๋ฆ์ด๋ module ๊ฒฝ๋ก๋ก ๊ณจ๋ผ ์คํํ๋ค.
๊ณต์ helper์ ์์น
์ฌ๋ฌ integration test๊ฐ ๊ฐ์ fixture๋ ์ค๋น ์ฝ๋๋ฅผ ์ด๋ค๋ฉด ๊ณต์ module์ ๋๋ค.
tests/
โโโ api.rs
โโโ parsing.rs
โโโ common/
โโโ mod.rs- ์ฐ๊ฒฐ: ๊ฐ ํ
์คํธ ํ์ผ์์
mod common;์ ์ ์ธํด helper ์ฌ์ฉ. - ์์น:
tests/common.rs๋ก ๋๋ฉด ๊ธฐ๋ณธ target ํ์์์ ๋ณ๋ integration test๋ก ์กํ.tests/common/mod.rs๋ helper module๋ก ์ฐ๊ฒฐ. - ์๋ ํ๋จ: ํ์ผ์ ๋ฌถ๋ ํจ๊ณผ๋ ๋น๋ยท๋งํฌ ์๊ฐ์ ๋ฐ๋ผ ๋ค๋ฆ. ์์ ํ ์คํธ ๋ชจ์๋ถํฐ ๋ณต์กํ๊ฒ ์ฌ๊ตฌ์ฑํ ํ์๋ ์ ์.
10. ๊ฒ์ฆ ๋์๋ณ ๋๊ตฌ ์ ํ
์์ ์์ ๋ ํ์ค ํ ์คํธ ์คํ๊ธฐ๋ง ์ฌ์ฉํ๋ค. Async ์คํ ํ๊ฒฝ์ด๋ ํฐ ์ถ๋ ฅ, ๋ค์ํ ์ ๋ ฅ์ ๊ฒ์ฌํ ํ์๊ฐ ์๊ธฐ๋ฉด ๋ชฉ์ ์ ๋ง๋ ๋๊ตฌ๋ฅผ ์ถ๊ฐํ๋ค.
| ๋๊ตฌ | ์ฌ์ฉํ ์ํฉ | ๊ฒ์ฆ ๋ฐฉ์ |
|---|---|---|
#[tokio::test] | Tokio ๊ธฐ๋ฐ async ์ฝ๋ | ํ ์คํธ์ฉ runtime์ ๊ตฌ์ฑํด async ํจ์ ์คํ |
cargo-nextest | ํ ์คํธ ์คํยท์ ํยท๊ฒฐ๊ณผ ๋ณด๊ณ ๊ด๋ฆฌ | unitยทintegration test ์คํ ๋ฐฉ์์ ํ์ฅ |
insta | ํ์ยทํฌ๋งคํฐ ๋ฑ์ ํฐ ์ถ๋ ฅ | ์ ์ฅํ snapshot๊ณผ ํ์ฌ ์ถ๋ ฅ์ ๋น๊ต |
proptest | ์ฌ๋ฌ ์ ๋ ฅ์์ ๊ท์น์ด ์ ์ง๋๋์ง ํ์ธ | ์ ๋ ฅ์ ์์ฑํด ๊ฒ์ฆํ๊ณ ์คํจํ ์ ๋ ฅ์ ๋จ์ํ |
์๋ฅผ ๋ค์ด ๋ฐฐ์ก๋น ๊ท์น์ ์ฌ๋ฌ ๊ธ์ก์ผ๋ก ํ์ธํ๋ ค๋ฉด proptest๋ก ํฉ๊ณ๋ฅผ ์์ฑํ๊ณ ๊ท์น์ ๊ฒ์ฌํ๋ค. ์ฃผ๋ฌธ ๋ช ์ธ์๋ฅผ ๋ฌธ์์ด๋ก ์ถ๋ ฅํ๋ ๊ธฐ๋ฅ์ด๋ผ๋ฉด insta๋ก ์ถ๋ ฅ ์ ์ฒด์ ๋ณ๊ฒฝ์ ๋น๊ตํ๋ค.
Nextest ๋ฒ์: ๋ฌธ์ ํ ์คํธ๋ ๋ณ๋ ์คํ
- ์คํ ๋์: Nextest๋ unitยทintegration test๋ฅผ ์คํ. ๋ฌธ์ ํ ์คํธ๋ ํ์ฌ ๋ณ๋ Cargo ๋ช ๋ น์ผ๋ก ์คํ.
- ์๋: ๋ณ๋ ฌ ์คํ ๋ฑ์ ํจ๊ณผ๋ ํ ์คํธ ๊ตฌ์ฑ๊ณผ ์คํ ์๊ฐ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง.
# Nextest๋ฅผ ์ค์นํด ์ฌ์ฉํ๋ ํ๊ฒฝ
cargo nextest run
cargo test --doc