본문으로 건너뛰기

안동민 개발노트

본문 시작

테스트 작성 방법

테스트 함수와 assert 계열 매크로로 결과·동등성·패닉을 검증하고 Result를 반환하는 실패 검사 방식을 익힙니다.

에츠허르 다익스트라(Edsger W. Dijkstra)는 1972년 자신의 에세이 ‘겸손한 프로그래머(The Humble Programmer)’에서 ‘프로그램 테스트는 버그의 존재를 보여주는 데에는 매우 효율적인 방법일 수 있지만, 버그의 부재를 보여주기에는 절망적으로 부적절하다’라고 말했습니다.

그렇다고 해서 가능한 많은 테스트를 시도하지 말아야 한다는 뜻은 아닙니다!

프로그램의 정확성은 곧 ‘프로그램이 얼마나 의도한 대로 작동하는가’와 같습니다.

러스트는 프로그램의 정확성에 굉장히 신경을 써서 설계된 언어지만, 정확성을 증명하기란 어렵고 복잡합니다.

러스트 타입 시스템이 이 역할의 큰 부담을 해소해 주고 있으나 타입 시스템만으로 모든 문제를 잡아내지는 못합니다.

따라서 러스트는 언어 자체적으로 자동화된 소프트웨어 테스트 작성을 지원합니다.

Cargo가 선택한 패키지와 테스트 대상을 컴파일하고 테스트 실행기가 test 함수를 발견한 뒤 준비, 실행, 단언을 거쳐 참, 예상한 패닉, Ok 반환의 통과 근거 또는 거짓, 예상 밖 패닉, 예상한 패닉의 부재나 expected 문자열 불일치, Err 반환의 실패 근거를 남기고 선택된 집합의 요약과 부분 문자열 필터 재실행으로 이어지는 흐름

Rust · cargo test · flowchart

테스트는 범위를 고르고, 계약을 실행하고, 근거로 다시 좁힌다

컴파일 성공은 타입·대여 규칙을, 테스트 결과는 기대 동작을 확인합니다. Cargo가 고른 패키지·대상의 테스트 코드를 컴파일하면 테스트 실행기가 #[test] 함수를 발견하고, 준비, 실행, 단언의 결과를 선택된 집합의 요약으로 보고합니다.

Rust 테스트 실행과 실패 근거 확인 흐름 cargo test의 패키지, 대상, 이름 필터 범위를 정한 뒤 테스트 코드를 컴파일하고 test 함수를 발견한다. 테스트는 준비, 실행, 단언으로 이어지고, 계약이 성립하면 참, 예상한 패닉, Ok 반환을 통과 근거로 남기며 성립하지 않으면 거짓, 예상 밖 패닉, 예상한 패닉의 부재나 expected 문자열 불일치, Err 반환을 실패 근거로 남긴다. 마지막 요약에서 이름의 부분 문자열 필터로 범위를 줄여 다시 실행할 수 있다. PASS FAIL FILTERED RERUN cargo test 범위 선택 package · target · name filter 테스트 코드 컴파일 · 발견 rustc --test · #[test] · libtest 준비 input · state · fixture 실행 call target · observe actual 기대 계약이 성립하는가? bool · equality · panic · Termination 통과 근거 true · expected panic · Ok(()) 실패 근거 false · panic contract miss · Err(E) 요약 확인 · 필터 재실행 counts · cargo test name_filter

scope · discovery

1. 실행할 패키지·대상을 고르고 컴파일

Cargo는 선택된 패키지와 테스트 대상을 컴파일합니다. 일반 테스트 실행 바이너리에서는 #[test] 함수가 실행 대상으로 발견됩니다.

arrange

2. 입력과 상태 준비

테스트가 필요한 입력, fixture, 초기 상태를 작고 독립적인 범위에 둡니다.

act

3. 검사할 동작 실행

대상 함수나 메서드를 호출해 실제 값 또는 실패 결과를 얻습니다.

assert

4. 기대 계약과 실제 결과 비교

bool, 동등성, 예상한 패닉, 또는 반환형의 Termination 결과로 통과와 실패를 가릅니다.

evidence

5. 통과·실패 근거 읽기

참, 예상한 패닉, Ok(())는 계약에 따라 통과할 수 있습니다. 거짓, 예상 밖 패닉, 예상한 패닉의 부재나 expected 문자열 불일치, Err(E)는 실패 근거가 됩니다.

summary · rerun

6. 선택된 집합을 요약하고 다시 좁히기

cargo test name_filter는 전체 테스트 경로의 부분 문자열 필터이므로 여러 테스트를 고를 수 있습니다. 각 테스트 실행 바이너리 안의 함수들은 기본적으로 병렬 실행됩니다.

여러 일반 테스트 대상은 별도 실행 바이너리로 순차 실행되지만, 각 바이너리 안의 테스트 함수는 기본적으로 병렬 실행됩니다. 공유 상태나 완료 순서에 의존하지 말고, 직렬 실행이 필요하면 cargo test -- 뒤에 --test-threads=1을 전달합니다.

전달받은 숫자에 2를 더하는 add_two 함수를 작성한다고 칩시다.

함수 시그니처는 매개변수로 정수를 전달받고, 결과로 정수를 반환합니다.

이 함수를 구현하고 컴파일할 때 러스트는 앞서 배운 타입 검사 및 대여 검사를 수행합니다.

함수에 String 값이나 유효하지 않은 참조자가 전달될 일이 없도록 보장해 주죠.

하지만 러스트는 함수가 의도대로 작동하는지에 대해서는 검사할 수 없습니다.

함수가 매개변수에 2를 더하지 않고, 10을 더하거나 50을 빼서 반환해도 모를 일입니다!

이런 경우에 테스트를 도입합니다.

예를 들어 add_two 함수에 3을 전달하면 5가 반환될 것임을 단언(assert) 하는 테스트를 작성하고 코드를 수정할 때마다 테스트를 실행하면, 제대로 작동하던 기존 코드에 문제가 생기지 않았을지 걱정할 필요가 없습니다.

테스트는 복잡한 기술입니다.

이번 장에서 좋은 테스트를 작성하는 방법에 대한 모든 것을 전부 다룰 수는 없습니다.

이번 장은 러스트의 테스트 메커니즘을 설명합니다.

테스트 작성 시 사용하는 어노테이션, 매크로를 배우고, 테스트 실행 시의 기본 동작과 실행 옵션, 유닛 테스트와 통합 테스트를 조직화하는 방법을 배워보도록 하죠.

이제 테스트를 설계하고 실행하는 기본 흐름을 살펴보겠습니다.

테스트란, 테스트할 코드가 의도대로 기능하는지 검증하는 함수입니다.

테스트 함수는 보통 본문에서 세 가지 동작을 수행합니다.

  1. 필요한 데이터나 상태 설정
  2. 테스트할 코드 실행
  3. 의도한 결과가 나오는지 확인

test 속성(attribute), 몇 가지 매크로, should_panic 속성을 포함하여 위 세 가지 동작을 수행하는 테스트를 위해 러스트가 특별히 제공하는 기능을 살펴봅시다.


테스트 함수 파헤치기

간단히 말해서, 러스트에서 테스트란 test 속성이 어노테이션된 함수입니다.

속성은 러스트 코드 조각에 대한 메타데이터입니다.

앞서 5장에서 구조체에 사용했던 derive도 속성 중 하나입니다.

함수의 fn 이전 줄에 #[test]를 추가하면 테스트 함수로 변경됩니다.

테스트는 cargo test 명령어로 실행됩니다. Cargo는 먼저 선택된 패키지와 테스트 대상의 코드를 테스트 모드로 컴파일하고, 일반 단위·통합 테스트 대상에는 #[test] 함수들을 발견하고 결과를 보고하는 테스트 실행 바이너리를 만듭니다. 문서 테스트는 rustdoc이 별도로 처리합니다.

Cargo로 새 라이브러리 프로젝트를 생성할 때마다 테스트 함수가 포함된 테스트 모듈이 자동 생성됩니다.

이 모듈이 테스트 작성을 위한 템플릿을 제공하므로, 새 프로젝트를 시작할 때마다 정확한 구조 및 테스트 함수 문법을 찾아볼 필요는 없습니다.

테스트 모듈과 테스트 함수는 여러분이 원하는 만큼 추가할 수 있습니다!

어떤 코드를 실제로 테스트해 보기 전에, 먼저 이 템플릿 테스트를 가지고 실험해 보면서 테스트가 어떻게 작동하는지 알아보겠습니다.

그다음 실제로 우리가 작성한 코드가 제대로 작동하는지 확인하는 테스트를 직접 작성해보겠습니다.

두 숫자를 더하는 adder라는 라이브러리 프로젝트를 생성해봅시다.

$ cargo new adder --lib
     Created library `adder` project
$ cd adder

adder 라이브러리의 src/lib.rs 파일 내용은 다음과 같습니다.

예제 10-1: cargo new 명령어로 자동 생성된 테스트 모듈과 함수
src/lib.rs
#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        let result = 2 + 2;
        assert_eq!(result, 4);
    }
}

맨 위 두 줄은 무시하고 함수에 집중합시다.

#[test] 어노테이션을 주목해 주세요.

이 속성은 해당 함수가 테스트 함수임을 표시하며, 테스트 실행기는 이 표시를 보고 해당 함수를 테스트로 다룰 수 있게 됩니다.

tests 모듈 내에는 테스트 함수뿐만 아니라, 일반적인 시나리오를 설정하거나 자주 쓰이는 연산을 수행하는 일반 함수도 작성하기도 하므로, 어떤 함수가 테스트 함수인지 항상 표시해 줘야 합니다.

예제 함수 본문에서는 assert_eq! 매크로를 사용하여 result에 대한 단언(assert)을 했는데, 이 변수의 내용물이 2와 2를 더한 결과인 4와 같다는 것입니다. assert_eq!assert_ne!PartialEq로 값을 비교하고, 실패 시 Debug 표현으로 좌우 값을 보여주므로 비교 대상에는 두 트레이트가 필요합니다.

이 단언 코드는 일반적인 테스트 형식 예제로써 제공됩니다.

한번 테스트를 실행해 이 테스트가 통과되는지 확인해 보죠.

선택 옵션 없이 cargo test를 실행하면 현재 매니페스트가 정하는 패키지와 Cargo의 기본 테스트 대상 집합을 빌드하고 실행합니다. 워크스페이스의 모든 패키지와 모든 종류의 대상을 무조건 고르는 명령은 아니며, 패키지·대상·기능 옵션을 주면 범위가 달라집니다.

여러 일반 테스트 대상이 있으면 각 대상은 별도의 테스트 실행 바이너리가 되고, Cargo는 이 실행 바이너리들을 순차적으로 실행합니다. 각 바이너리 안에서 선택된 테스트 함수들은 기본적으로 여러 스레드에서 병렬 실행되므로 완료 순서나 공유 상태에 의존해서는 안 됩니다. 필요하다면 cargo test -- --test-threads=1로 한 스레드 실행을 요청할 수 있습니다.

결과는 예제 10-2처럼 나타납니다.

예제 10-2: 자동 생성된 테스트 실행 결과
$ cargo test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished test [unoptimized + debuginfo] target(s) in 0.57s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 1 test
test tests::it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Cargo와 테스트 실행기의 출력 형식, 실행 파일 해시, 파일 경로는 도구체인 버전과 환경에 따라 달라질 수 있습니다. 아래 출력 예시들도 같은 원칙으로 읽으세요.

Cargo가 테스트를 컴파일하고 실행했습니다.

running 1 test 줄이 보입니다.

그다음 줄에는 생성된 테스트 함수의 이름 it_works와 테스트 실행 결과 ok가 표시됩니다.

전체 요약 test result: ok.는 모든 테스트가 통과됐다는 뜻이고, 1 passed; 0 failed라는 부분은 통과하거나 실패한 테스트 개수를 종합합니다.

어떤 테스트를 무시하도록 표시하여 특정 인스턴스에서는 실행되지 않도록 할 수도 있습니다; 이에 대해서는 이 장의 ‘특별 요청이 없다면 일부 테스트 무시하기’절에서 다루겠습니다.

이번 예제에는 그런 게 없었으므로, 요약에는 0 ignored가 표시됩니다.

또한 cargo test name_filter처럼 인수를 넘기면 전체 테스트 경로에 해당 문자열이 포함된 테스트들만 실행할 수 있습니다. 이는 정확히 하나를 지정하는 이름이 아니라 부분 문자열 필터(filter) 이므로 여러 테스트가 함께 선택될 수 있습니다. 자세한 내용은 ‘이름을 지정해 일부 테스트만 실행하기’절에서 다룰 예정입니다.

지금의 테스트에서는 필터링도 없었으므로, 요약의 끝부분에 0 filtered out이 표시됩니다.

0 measured 통계는 성능 측정 벤치마크 테스트용입니다.

이 내용이 작성된 시점을 기준으로, 벤치마크 테스트는 러스트 나이틀리(nightly)에서만 사용 가능합니다.

자세한 내용은 벤치마크 테스트 문서를 참고해 주세요.

테스트 출력 결과 중 Doc-tests adder로 시작하는 부분은 문서 테스트 결과를 나타냅니다.

아직 문서 테스트를 작성해 보진 않았지만, 러스트는 API 문서에 작성해 놓은 예제 코드도 컴파일 할 수 있습니다.

러스트의 이 기능은 작성한 코드와 문서의 내용이 달라지지 않도록 유지보수하는 데에 매우 유용하답니다!

문서 테스트 작성 방법은 13장의 ‘테스트로서의 문서화 주석’절에서 배울 예정입니다.

지금은 일단 Doc-tests 출력을 무시하겠습니다.

현재의 요구사항에 맞게 테스트의 커스터마이징을 시작해봅시다.

먼저 다음과 같이 it_works 함수의 이름을 exploration 같은 다른 이름으로 변경해봅시다.

src/lib.rs
#[cfg(test)]
mod tests {
    #[test]
    fn exploration() {
        assert_eq!(2 + 2, 4);
    }
}

cargo test를 다시 실행하면 출력 결과에 it_works 대신 exploration이 나타납니다.

$ cargo test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished test [unoptimized + debuginfo] target(s) in 0.59s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 1 test
test tests::exploration ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

이제 다른 테스트를 추가하는데, 이번엔 테스트가 실패하도록 만들어 보죠!

일반 테스트 함수가 예상하지 않은 패닉으로 끝나면 테스트 실행기는 해당 테스트를 실패로 기록합니다. 기본 테스트 실행기는 선택된 테스트 함수들을 병렬로 실행하지만, 각 테스트가 반드시 새 스레드 하나와 일대일로 대응한다는 구현 세부에는 의존하지 않는 편이 좋습니다.

9장에서, 가장 쉽게 패닉을 일으키는 방법은 panic 매크로를 호출하는 것이라고 이야기했습니다.

예제 10-3처럼 src/lib.rs 파일에 another라는 테스트를 새로 추가해봅시다.

예제 10-3: panic! 매크로를 호출하여 실패하도록 만든 테스트 추가
src/lib.rs
#[cfg(test)]
mod tests {
    #[test]
    fn exploration() {
        assert_eq!(2 + 2, 4);
    }

    #[test]
    fn another() {
        panic!("Make this test fail");
    }
}

cargo test를 다시 실행해 보죠.

출력 결과는 예제 10-4처럼 exploration 테스트는 통과하고 another 테스트는 실패했다고 나타날 겁니다.

예제 10-4: 테스트 하나는 통과하고 다른 하나는 실패했을 때의 테스트 결과
$ cargo test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished test [unoptimized + debuginfo] target(s) in 0.72s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 2 tests
test tests::another ... FAILED
test tests::exploration ... ok

failures.

---- tests::another stdout ----
thread 'tests::another' panicked at 'Make this test fail', src/lib.rs:10:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

failures.
    tests::another

test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`

test tests::another 줄은 ok가 아니라 FAILED로 표시됩니다.

개별 결과와 요약 사이에 새로운 절이 두 개 나타났네요.

첫 번째 절은 테스트가 실패한 자세한 이유를 보여줍니다. 실패 근거는 명시적인 panic!, 실패한 assert!·assert_eq!, 혹은 Termination을 통해 실패로 보고된 Err(E) 등 계약에 따라 달라집니다. 메시지와 파일 위치가 제공되는 방식도 실패 종류와 도구체인 버전에 따라 다를 수 있습니다.

위의 경우 another 테스트는 panicked at 'Make this test fail'라는 이유로 실패했으며, src/lib.rs 파일 10번째 줄에서 발생했다는 세부 사항을 알게 되었습니다.

다음 절은 실패한 테스트의 이름을 목록으로 보여줍니다.

이는 테스트가 많아지고 테스트 실패 사유 출력량도 많아졌을 때 유용합니다.

실패한 테스트의 전체 경로에서 고유한 문자열을 필터로 사용하면 출력 범위를 줄여 디버깅할 수 있습니다. 필터는 부분 문자열과 일치하는 모든 테스트를 선택하므로, 문자열이 고유하지 않다면 하나만 실행된다고 보장할 수 없습니다.

테스트를 실행하는 각종 방식은 ‘테스트 실행 방법 제어하기’절에서 다룰 예정입니다.

요약 줄은 마지막에 출력됩니다.

종합적인 테스트 결과는 FAILED군요.

테스트 하나는 통과했지만, 테스트 하나가 실패했습니다.

각 상황에서 테스트 실행 결과가 어떻게 나타나는지 살펴봤으니, panic! 이외에 테스트에서 유용하게 쓰이는 매크로를 알아봅시다.


assert! 매크로로 결과 검사하기

어떤 조건이 true임을 보장하는 테스트를 작성할 땐 표준 라이브러리가 제공하는 assert! 매크로가 유용합니다.

assert! 매크로는 참·거짓처럼 취급되는 임의의 값이 아니라 실제 bool 타입 표현식을 전달받습니다.

true 값일 경우, 아무 일도 일어나지 않고 테스트는 통과합니다.

false 값일 경우, assert! 매크로는 panic! 매크로를 호출하여 테스트를 실패하도록 만듭니다.

assert! 매크로를 사용하면 작성한 코드가 의도대로 기능하는지 검사하는 데에 유용합니다.

4장 예제 4-15에서 Rectangle 구조체랑 can_hold 메서드를 사용했었죠. (예제 10-5로 다시 보여드립니다.)

이 코드를 src/lib.rs 파일에 작성하고, 그다음 assert! 매크로로 테스트를 작성해봅시다.

예제 10-5: 4장 Rectangle 구조체와 can_hold 메서드
src/lib.rs
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
}

can_hold 메서드는 부울린 값을 반환하니 assert 매크로 사용 예시로 쓰기에 딱 알맞습니다.

예제 10-6은 can_hold 메서드를 시험하는 테스트를 작성한 모습입니다.

너비 8, 높이 7 Rectangle 인스턴스를 생성하고, 이 인스턴스는 너비 5, 높이 1 Rectangle 인스턴스를 포함할 수 있음을 단언합니다.

예제 10-6: 큰 사각형이 작은 사각형을 정말로 포함할 수 있는지 검사하는 can_hold 메서드 테스트
src/lib.rs
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn larger_can_hold_smaller() {
        let larger = Rectangle {
            width: 8,
            height: 7,
        };
        let smaller = Rectangle {
            width: 5,
            height: 1,
        };

        assert!(larger.can_hold(&smaller));
    }
}

tests 모듈에 use super::*; 줄이 추가되었습니다.

tests 모듈 또한 6장 ‘경로를 사용하여 모듈 트리의 아이템 참조하기’절에서 다룬 가시성 규칙을 따르는 평범한 모듈입니다.

따라서, 내부 모듈인 tests 모듈에서 외부 모듈의 코드를 테스트하려면 먼저 내부 스코프로 가져와야 합니다.

tests 모듈에서는 글롭(*)을 사용해 외부 모듈에 정의된 걸 전부 사용할 수 있도록 하였습니다.

테스트 이름은 larger_can_hold_smaller로 정하고, 필요한 Rectangle 인스턴스를 두 개 생성하고, larger.can_hold(&smaller) 호출 결과를 전달하여 assert! 매크로를 호출하였습니다.

larger.can_hold(&smaller) 표현식은 true를 반환할 테니 테스트는 성공하겠죠.

확인해봅시다!

$ cargo test
   Compiling rectangle v0.1.0 (file:///projects/rectangle)
    Finished test [unoptimized + debuginfo] target(s) in 0.66s
     Running unittests src/lib.rs (target/debug/deps/rectangle-6584c4561e48942e)

running 1 test
test tests::larger_can_hold_smaller ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests rectangle

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

통과됐네요!

이번에는 작은 사각형이 큰 사각형을 포함할 수 없음을 단언하는 테스트를 추가해봅시다.

src/lib.rs
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn larger_can_hold_smaller() {
        // --생략--
    }

    #[test]
    fn smaller_cannot_hold_larger() {
        let larger = Rectangle {
            width: 8,
            height: 7,
        };
        let smaller = Rectangle {
            width: 5,
            height: 1,
        };

        assert!(!smaller.can_hold(&larger));
    }
}

이번에는 can_hold 함수가 false를 반환해야 하니, assert! 매크로에 전달하기 전에 논리 부정 연산자를 사용했습니다.

결과적으로, 이 테스트는 can_hold 함수에서 false 값을 반환하면 성공합니다.

$ cargo test
   Compiling rectangle v0.1.0 (file:///projects/rectangle)
    Finished test [unoptimized + debuginfo] target(s) in 0.66s
     Running unittests src/lib.rs (target/debug/deps/rectangle-6584c4561e48942e)

running 2 tests
test tests::larger_can_hold_smaller ... ok
test tests::smaller_cannot_hold_larger ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests rectangle

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

두 테스트를 모두 통과했습니다!

그러면 이제 코드에 버그가 있으면 테스트 결과가 어떻게 되는지 알아보죠.

can_hold 메서드 구현부 중 너비 비교 부분의 큰 부등호를 작은 부등호로 바꿔보겠습니다.

// --생략--
impl Rectangle {
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width < other.width && self.height > other.height
    }
}

테스트 실행 결과는 다음과 같습니다.

$ cargo test
   Compiling rectangle v0.1.0 (file:///projects/rectangle)
    Finished test [unoptimized + debuginfo] target(s) in 0.66s
     Running unittests src/lib.rs (target/debug/deps/rectangle-6584c4561e48942e)

running 2 tests
test tests::larger_can_hold_smaller ... FAILED
test tests::smaller_cannot_hold_larger ... ok

failures.

---- tests::larger_can_hold_smaller stdout ----
thread 'tests::larger_can_hold_smaller' panicked at 'assertion failed: larger.can_hold(&smaller)', src/lib.rs:28:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

failures.
    tests::larger_can_hold_smaller

test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`

테스트로 버그를 찾아냈네요!

larger.width는 8이고 smaller.width는 5인데 can_hold의 너비 비교 결과는 false(larger.widthsmaller.width 보다 작음)를 반환합니다.

8이 5보다 작진 않죠.

테스트 함수가 실제로 읽히는 방식은 준비, 실행, 단언, 실패 메시지를 어디에 둘지에 따라 달라집니다.


이어서 보기