← Rust 강의 목록으로
🦀
모던 Rust
모던 · 선수: 19강

20. 단위 테스트·통합 테스트·doctest

Rust 는 테스트 러너가 cargo 에 내장돼 있습니다. #[test] 어트리뷰트를 함수에 붙이면 cargo test 가 자동으로 모아 실행. 단위 테스트(같은 파일의 mod tests), 통합 테스트(tests/ 폴더), 그리고 문서 안의 코드 블록을 자동 실행하는 doctest 까지 한 번에 정리합니다.

Rusttestcargo testdoctestassert_eqTDD
소요 시간
약 1.5시간
난이도
📊 중급
선수 조건
🎯 19강
결과물
Rust 는 테스트 러너가 cargo 에 내장돼 있습니다. #[test] 어트리뷰트를 함수에 붙이면 cargo test 가 자동으로 모아 실행. 단위 테스트(같은 파일의 mod tests), 통합 테스트(tests/ 폴더), 그리고 문서 안의 코드 블록을 자동 실행하는 doctest 까지 한 번에 정리합니다.

이 강의에서 배우는 것

  • 1#[test] 함수를 작성하고 cargo test 로 실행한다
  • 2단위 테스트의 mod tests 관례를 따른다
  • 3통합 테스트를 tests/ 폴더에 분리해 작성한다
  • 4#[should_panic] 으로 패닉 검증 테스트를 작성한다
  • 5/// 주석 안의 예제 코드를 doctest 로 실행한다

소개

테스트가 별도 도구 없이 cargo 안에 들어 있다는 것은 큰 이점입니다. "테스트 프레임워크 뭘 쓰지" 같은 결정을 할 필요가 없고, 새 프로젝트도 처음부터 테스트를 자연스럽게 작성할 수 있습니다.

핵심 개념

1) 단위 테스트 — 같은 파일 안 mod tests

rust
pub fn add(a: i32, b: i32) -> i32 { a + b }

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn add_works() {
        assert_eq!(add(2, 3), 5);
    }

    #[test]
    fn add_negative() {
        assert_eq!(add(-1, 1), 0);
    }
}
  • `#[cfg(test)]` — 테스트 빌드에서만 컴파일
  • `use super::*` — 부모 모듈의 private 항목까지 접근 가능
  • `#[test]` 가 붙은 fn 만 cargo test 가 실행

2) 통합 테스트 — tests/ 폴더

라이브러리의 공개 API 만 사용해 전체 동작을 검증. 외부 사용자가 쓰는 것과 같은 경로.

rust
// tests/api.rs
use my_crate::add;

#[test]
fn integration_add() {
    assert_eq!(add(10, 20), 30);
}

3) 자주 쓰는 assert 매크로

매크로용도
assert!(expr)expr 이 true 여야
assert_eq!(a, b)a == b
assert_ne!(a, b)a != b
#[should_panic]테스트 함수가 panic 해야 통과
#[ignore]기본 실행에서 제외 (cargo test -- --ignored)

4) doctest — /// 안의 예제 코드 실행

rust
/// 두 수를 더합니다.
///
/// # 예제
///
/// ```
/// assert_eq!(my_crate::add(2, 3), 5);
/// ```
pub fn add(a: i32, b: i32) -> i32 { a + b }

핵심 예제

Result 반환 테스트와 should_panic:

rust
pub fn divide(a: i32, b: i32) -> i32 {
    if b == 0 { panic!("div by zero"); }
    a / b
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn ok_case() -> Result<(), String> {
        if divide(10, 2) == 5 { Ok(()) } else { Err("expected 5".into()) }
    }

    #[test]
    #[should_panic(expected = "div by zero")]
    fn panic_case() { divide(10, 0); }
}

실행 명령:

bash
cargo test                  # 전체
cargo test add_              # 이름에 add_ 가 포함된 것만
cargo test -- --nocapture    # println! 출력 보기
cargo test --doc             # doctest 만
cargo test -- --ignored      # ignore 된 것 실행

자주 하는 실수

Q. cargo test 출력에 println! 이 안 보입니다

A. 기본 동작입니다 — 성공한 테스트의 출력은 가려집니다. `cargo test -- --nocapture` 로 켤 수 있습니다.

Q. tests/ 폴더와 mod tests 의 차이는?

A. **mod tests** = 같은 crate 내부 private 까지 접근 가능. **tests/** = 외부 사용자 시점에서 public API 만 호출. 둘을 함께 쓰는 것이 일반적.

Q. 테스트가 너무 느립니다

A. cargo test 는 기본적으로 병렬 실행합니다. 직렬이 필요하면 `cargo test -- --test-threads=1`. 특정 테스트만 `--ignored` 로 분리해 평소 실행에서 빼는 것도 방법.

정리

  • cargo test 가 #[test] 함수를 자동 수집·실행
  • mod tests + #[cfg(test)] = 단위 테스트 관례
  • tests/ 폴더 = 통합 테스트 (public API 만)
  • /// 안 코드 블록 = doctest 자동 실행
  • should_panic·ignore·assert_eq 매크로 활용

과제

  1. 기존 라이브러리 함수에 mod tests 를 붙이고 3개 이상 단위 테스트 작성
  2. tests/api.rs 에 통합 테스트 하나 추가
  3. /// 주석 예제 코드를 추가하고 cargo test --doc 으로 통과 확인
예제 코드 / 강의 자료

전체 강의 자료와 예제 코드는 GitHub에서 자유롭게 받아볼 수 있습니다.

GitHub에서 보기 ↗