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 함수입니다. 테스트 함수의 본문은 일반적으로 설정을 수행하고, 테스트하려는 코드를 실행한 다음, 결과가 예상과 일치하는지 단언(assert)합니다.

대부분의 유닛 테스트는 #[cfg(test)] 속성이 있는 tests 모듈에 들어갑니다. 테스트 함수는 #[test] 속성으로 표시됩니다.

테스트 함수 내에서 패닉이 발생하면 테스트가 실패합니다. 다음과 같은 몇 가지 도우미 매크로가 있습니다:

  • assert!(expression) - 표현식의 평가 결과가 false이면 패닉을 발생시킵니다.
  • assert_eq!(left, right)assert_ne!(left, right) - 왼쪽과 오른쪽 표현식이 각각 같은지 또는 다른지를 테스트합니다.
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

// 이것은 정말 형편없는 더하기 함수입니다. 이 예제에서 실패하도록 만드는 것이 목적입니다.
#[allow(dead_code)]
fn bad_add(a: i32, b: i32) -> i32 {
    a - b
}

#[cfg(test)]
mod tests {
    // 이 유용한 관용구를 기억하세요: 외부 스코프(mod tests의 경우)에서 이름들을 가져옵니다.
    use super::*;

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

    #[test]
    fn test_bad_add() {
        // 이 단언(assert)은 실행될 것이고 테스트는 실패할 것입니다.
        // 참고로, 프라이빗 함수도 테스트할 수 있습니다!
        assert_eq!(bad_add(1, 2), 3);
    }
}

테스트는 cargo test로 실행할 수 있습니다.

$ cargo test

running 2 tests
test tests::test_bad_add ... FAILED
test tests::test_add ... ok

failures:

---- tests::test_bad_add stdout ----
        thread 'tests::test_bad_add' panicked at 'assertion failed: `(left == right)`
  left: `-1`,
 right: `3`', src/lib.rs:21:8
note: Run with `RUST_BACKTRACE=1` for a backtrace.


failures:
    tests::test_bad_add

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

테스트와 ?

이전의 유닛 테스트 예제들에는 반환 타입이 없었습니다. 하지만 Rust 2018에서는 유닛 테스트가 Result<()>를 반환할 수 있어, 테스트 내에서 ?를 사용할 수 있습니다! 이를 통해 테스트를 훨씬 더 간결하게 만들 수 있습니다.

fn sqrt(number: f64) -> Result<f64, String> {
    if number >= 0.0 {
        Ok(number.powf(0.5))
    } else {
        Err("음수 부동 소수점은 제곱근을 가질 수 없습니다".to_owned())
    }
}

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

    #[test]
    fn test_sqrt() -> Result<(), String> {
        let x = 4.0;
        assert_eq!(sqrt(x)?.powf(2.0), x);
        Ok(())
    }
}

더 자세한 내용은 “The Edition Guide”를 참조하세요.

패닉 테스트

특정 상황에서 패닉이 발생해야 하는 함수를 확인하려면 #[should_panic] 속성을 사용합니다. 이 속성은 선택적 파라미터 expected = 를 받으며, 패닉 메시지의 텍스트를 확인합니다. 만약 여러분의 함수가 여러 방식으로 패닉을 일으킬 수 있다면, 이 파라미터는 예상한 패닉이 발생했는지 확인하는 데 도움이 됩니다.

참고: Rust는 #[should_panic = "message"]와 같은 단축 형태도 허용하며, 이는 #[should_panic(expected = "message")]와 정확히 똑같이 작동합니다. 둘 다 유효하지만, 후자가 더 일반적으로 사용되며 더 명시적인 것으로 간주됩니다.

pub fn divide_non_zero_result(a: u32, b: u32) -> u32 {
    if b == 0 {
        panic!("0으로 나누기 에러");
    } else if a < b {
        panic!("나눗셈 결과가 0입니다");
    }
    a / b
}

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

    #[test]
    fn test_divide() {
        assert_eq!(divide_non_zero_result(10, 2), 5);
    }

    #[test]
    #[should_panic]
    fn test_any_panic() {
        divide_non_zero_result(1, 0);
    }

    #[test]
    #[should_panic(expected = "나눗셈 결과가 0입니다")]
    fn test_specific_panic() {
        divide_non_zero_result(1, 10);
    }

    #[test]
    #[should_panic = "나눗셈 결과가 0입니다"] // 이 방식도 작동합니다
    fn test_specific_panic_shorthand() {
        divide_non_zero_result(1, 10);
    }
}

이 테스트들을 실행하면 다음과 같은 결과를 얻습니다:

$ cargo test

running 4 tests
test tests::test_any_panic ... ok
test tests::test_divide ... ok
test tests::test_specific_panic ... ok
test tests::test_specific_panic_shorthand ... ok

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

   Doc-tests tmp-test-should-panic

running 0 tests

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

특정 테스트 실행하기

특정 테스트를 실행하려면 cargo test 명령에 테스트 이름을 지정하면 됩니다.

$ cargo test test_any_panic
running 1 test
test tests::test_any_panic ... ok

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

   Doc-tests tmp-test-should-panic

running 0 tests

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

여러 테스트를 실행하려면 실행하려는 모든 테스트와 매칭되는 테스트 이름의 일부분을 지정하면 됩니다.

$ cargo test panic
running 3 tests
test tests::test_any_panic ... ok
test tests::test_specific_panic ... ok
test tests::test_specific_panic_shorthand ... ok

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

   Doc-tests tmp-test-should-panic

running 0 tests

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

테스트 무시하기

일부 테스트를 제외하기 위해 #[ignore] 속성을 표시할 수 있습니다. 또는 cargo test -- --ignored 명령으로 무시된 테스트들만 실행할 수도 있습니다.

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

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

    #[test]
    fn test_add() {
        assert_eq!(add(2, 2), 4);
    }

    #[test]
    fn test_add_hundred() {
        assert_eq!(add(100, 2), 102);
        assert_eq!(add(2, 100), 102);
    }

    #[test]
    #[ignore]
    fn ignored_test() {
        assert_eq!(add(0, 0), 0);
    }
}
$ cargo test
running 3 tests
test tests::ignored_test ... ignored
test tests::test_add ... ok
test tests::test_add_hundred ... ok

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

   Doc-tests tmp-ignore

running 0 tests

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

$ cargo test -- --ignored
running 1 test
test tests::ignored_test ... ok

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

   Doc-tests tmp-ignore

running 0 tests

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