Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

문서 테스트

Rust 프로젝트를 문서화하는 기본 방법은 소스 코드에 주석을 다는 것입니다. 문서화 주석은 CommonMark Markdown 명세로 작성되며 코드 블록을 지원합니다. Rust는 올바름(correctness)을 중요하게 생각하므로, 이러한 코드 블록들은 컴파일되어 문서 테스트(documentation tests)로 사용됩니다.

/// 첫 번째 줄은 함수를 설명하는 짧은 요약입니다.
///
/// 다음 줄들은 상세한 문서화를 보여줍니다. 코드 블록은 백틱 세 개로 시작하며,
/// 내부적으로 암시적인 `fn main()`과 `extern crate <cratename>`을 가집니다.
/// `playground` 라이브러리 크레이트를 테스트하거나 플레이그라운드의
/// Test 액션을 사용하는 예시라고 가정해 봅시다:
///
/// ```
/// let result = playground::add(2, 3);
/// assert_eq!(result, 5);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

/// 일반적으로 문서 주석에는 "Examples", "Panics", "Failures" 섹션이 포함될 수 있습니다.
///
/// 다음 함수는 두 수를 나눕니다.
///
/// # Examples
///
/// ```
/// let result = playground::div(10, 2);
/// assert_eq!(result, 5);
/// ```
///
/// # Panics
///
/// 두 번째 인자가 0이면 함수가 패닉을 발생시킵니다.
///
/// ```rust,should_panic
/// // 0으로 나누기 시 패닉 발생
/// playground::div(10, 0);
/// ```
pub fn div(a: i32, b: i32) -> i32 {
    if b == 0 {
        panic!("0으로 나누기 에러");
    }

    a / b
}

문서 내의 코드 블록은 일반적인 cargo test 명령을 실행할 때 자동으로 테스트됩니다:

$ cargo test
running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

   Doc-tests playground

running 3 tests
test src/lib.rs - add (line 7) ... ok
test src/lib.rs - div (line 21) ... ok
test src/lib.rs - div (line 31) ... ok

test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

문서 테스트의 의도

문서 테스트의 주된 목적은 기능을 실행해보는 예시로서의 역할을 하는 것이며, 이는 가장 중요한 가이드라인 중 하나입니다. 이를 통해 문서의 예시를 완전한 코드 스니펫으로 사용할 수 있습니다. 하지만 main이 유닛 타입(unit)을 반환하기 때문에 ?를 사용하면 컴파일에 실패합니다. 이때 문서에서 일부 소스 라인을 숨길 수 있는 기능이 도움이 됩니다. fn try_main() -> Result<(), ErrorType>을 작성하고, 이를 숨긴 뒤 숨겨진 main에서 unwrap 할 수 있습니다. 복잡하게 들리나요? 여기 예시가 있습니다:

/// 문서 테스트에서 숨겨진 `try_main` 사용하기.
///
/// ```
/// # // `#` 기호로 시작하는 줄은 숨겨지지만, 여전히 컴파일 가능합니다!
/// # fn try_main() -> Result<(), String> { // 문서에 보여지는 본문을 감싸는 줄
/// let res = playground::try_div(10, 2)?;
/// # Ok(()) // try_main에서 반환
/// # }
/// # fn main() { // unwrap()을 호출할 main 시작
/// #    try_main().unwrap(); // try_main을 호출하고 unwrap하여
/// #                         // 에러 발생 시 테스트가 패닉을 일으키도록 함
/// # }
/// ```
pub fn try_div(a: i32, b: i32) -> Result<i32, String> {
    if b == 0 {
        Err(String::from("0으로 나누기"))
    } else {
        Ok(a / b)
    }
}

참고