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

테스트 작성 모범 사례

이 장에서는 테스트 작성 및 수정과 관련된 모범 사례를 설명합니다. 우리는 작성한 테스트가 몇 년이 지난 후에도 원래 작성자에게 문의하거나 git 기록을 잔뜩 파헤칠 필요 없이 이해하고 수정하기 쉽도록 하고자 합니다.

작성한 테스트를 검토할 때는, 몇 년 후 별다른 맥락 없이 실패한 테스트를 들여다보는 다른 기여자가 되었다고 가정하고 검토하는 것이 좋은 습관입니다(이는 며칠 또는 몇 달 후의 자기 자신에게도 도움이 됩니다!). 그런 다음 어떻게 하면 나와 그들의 삶을 더 편하게 만들 수 있을지 스스로에게 물어보십시오.

이를 실감 나게 이해할 수 있도록, 다른 기여자의 삶을 최대한 힘들게 만드는 테스트 작성법에 관한 여담부터 시작합시다.

여담: 간단한 테스트 방해 공작 야전 교범

다른 기여자의 삶을 최대한 힘들게 만들려면 다음과 같이 할 수 있습니다.

  • 다른 맥락 없이 이슈 번호만으로 테스트 이름을 짓습니다. 예: issue-123456.rs.
  • 테스트가 무엇을 검증하려는지에 대한 주석을 전혀 달지 않고, 관련 맥락으로 가는 링크도 남기지 않습니다.
  • (충분히 최소화할 수 있는데도) 거대하고, 테스트가 실제로 검증하려는 핵심에서 주의를 흐트러뜨리는 불필요한 부분이 포함된 테스트를 넣습니다.
  • 테스트가 확인하려는 내용에 중요하지 않은, 관련 없는 구문 오류와 기타 오류를 잔뜩 넣습니다.
  • 코드 조각을 이상하게 포매팅합니다.
  • 사용하지 않고 관련도 없는 기능을 잔뜩 넣습니다.
  • 예를 들어 ignore-windows compiletest 지시문을 넣되, 그것이 왜 필요한지는 전혀 설명하지 않습니다.

테스트 이름 짓기

독자가 이슈 번호를 입력하고 GitHub 검색을 뒤져 테스트가 무엇을 검증하려는지 찾아야 하는 대신, 테스트가 무엇을 검증하는지 즉시 이해할 수 있게 하십시오. 이렇게 하면 관련 테스트 묶음으로서 --test-args를 통해 테스트를 필터링할 수 있다는 추가 이점도 있습니다.

  • 테스트가 검증하려는 대상이나 회귀를 방지하려는 대상에 따라 테스트 이름을 지으십시오.
  • 간결하게 유지하십시오.
  • 이슈 번호만을 테스트 이름으로 사용하지 마십시오.
  • 자동 완성을 저하시키므로 테스트 이름을 issue-xxxxx 접두사로 시작하지 마십시오.

이슈 번호만을 테스트 이름으로 사용하지 마십시오

대신 테스트 주석에 링크나 #123456 형태로 포함하는 것을 권장합니다. 또는 이슈 번호를 포함하는 것이 타당하다면, macro-external-span-ice-123956.rs처럼 간략한 키워드도 함께 포함하십시오.

tests/ui/typeck/issue-123456.rs                              // bad
tests/ui/typeck/issue-123456-asm-macro-external-span-ice.rs  // bad (for tab completion)
tests/ui/typeck/asm-macro-external-span-ice-123456.rs        // good
tests/ui/typeck/asm-macro-external-span-ice.rs               // good

issue-123456.rs는 테스트가 실제로 무엇을 검증하는지 즉시 알려 주지 않으므로 추가로 검색해야 합니다. 테스트 이름에 이슈 번호를 접두사로 포함하면 탭 자동 완성의 유용성이 떨어집니다(테스트 디렉터리에서 ls를 실행했을 때 issue-xxxxx 접두사가 잔뜩 나오는 경우). 이슈 링크는 테스트 주석에 남기면 됩니다.

//! Check that `asm!` macro including nested macros that come from external
//! crates do not lead to a codepoint boundary assertion ICE.
//!
//! Regression test for <https://github.com/rust-lang/rust/issues/123456>.

이 규칙의 한 가지 예외는 크래시 테스트입니다. 크래시 테스트의 목적은 어떤 이슈의 코드 조각이 더 이상 ICE/크래시를 일으키지 않는지 추적하는 것이므로 테스트 이름을 이슈 번호만으로 짓는 것이 표준이며, 이러한 테스트는 수정 PR에서 제거되거나 적절한 ui 테스트 또는 기타 테스트로 변환됩니다.

테스트 구성

  • 대부분의 테스트 스위트에서는 테스트를 둘 의미상 적절한 하위 디렉터리를 찾으십시오.
    • 예를 들어 특히 RFC 2093의 구현이라면 tests/ui/rfc-2093-infer-outlives/ 아래에 테스트 모음을 묶어 둘 수 있습니다. 디렉터리 이름에는 해당 RFC가 무엇에 관한 것인지를 포함하십시오.
  • run-make/run-make-support 테스트 스위트의 경우, 각 rmake.rs는 각각 tests/run-make/ 또는 tests/run-make-cargo/ 바로 아래의 하위 디렉터리에 들어 있어야 합니다. 그보다 더 깊은 중첩은 현재 지원되지 않습니다. 테스트 이름에 이슈 번호만 사용하는 것도 피하십시오.

테스트 설명

다른 기여자가 자신의 변경으로 인해 테스트가 실패했을 때 그 테스트가 무엇에 관한 것인지 이해할 수 있도록, 테스트에 그 의도/목적에 대한 충분한 문서, 관련 맥락(이슈 번호나 기타 논의 포함)으로의 링크, 그리고 경우에 따라 관련 자료(예: 특정 동작에 대해서는 Win32 API로 링크하면 도움이 될 수 있습니다)가 갖춰져 있는지 확인해야 합니다.

좋은 주석이 달린 테스트의 개요

//! Brief summary of what the test is exercising.
//! Example: Regression test for #123456: make sure coverage attribute don't ICE
//!     when applied to non-items.
//!
//! Optional: Remarks on related tests/issues, external APIs/tools, crash
//!     mechanism, how it's fixed, FIXMEs, limitations, etc.
//! Example: This test is like `tests/attrs/linkage.rs`, but this test is
//!     specifically checking `#[coverage]` which exercises a different code
//!     path. The ICE was triggered during attribute validation when we tried
//!     to construct a `def_path_str` but only emitted the diagnostic when the
//!     platform is windows, causing an ICE on unix.
//!
//! Links to relevant issues and discussions. Examples below:
//! Regression test for <https://github.com/rust-lang/rust/issues/123456>.
//! See also <https://github.com/rust-lang/rust/issues/101345>.
//! See discussion at <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/123456-example-topic>.
//! See [`clone(2)`].
//!
//! [`clone(2)`]: https://man7.org/linux/man-pages/man2/clone.2.html

//@ ignore-windows
// Reason: (why is this test ignored for windows? why not specifically
// windows-gnu or windows-msvc?)

// Optional: Summary of test cases: What positive cases are checked?
// What negative cases are checked? Any specific quirks?

fn main() {
    #[coverage]
    //~^ ERROR coverage attribute can only be applied to function items.
    let _ = {
        // Comment highlighting something that deserves reader attention.
        fn foo() {}
    };
}

얼마나 많은 맥락/설명이 필요한지는 작성자와 리뷰어의 재량에 달려 있습니다. 테스트에서 다루는 사소하지 않은 부분에는 다른 기여자의 이해를 돕도록 어느 정도 설명을 붙이는 것이 좋은 경험 법칙입니다. 여기에는 다음에 대한 설명이 포함될 수 있습니다.

  • ICE나 버그가 꽤 복잡한 방식으로 발생하는 경우, 그것이 어떻게 발생하는지.
  • 관련 이슈와 테스트(예: 이 테스트는 다른 테스트와 비슷하지만 … 때문에 별도로 유지됩니다).
  • 플랫폼별 동작.
  • 외부 의존성과 API의 동작: 시스템 콜, 링커, 도구, 환경 등.

테스트 내용

  • 테스트를 가능한 한 최소화하도록 노력하십시오.
  • 중요하지 않은 코드를 최소화하고, 특히 stderr 스냅숏을 어지럽힐 수 있는 불필요한 구문 오류와 타입 오류를 최소화하십시오.
  • 관련 없는 경고를 억제하려면 #![allow(...)] 또는 #![expect(...)]를 사용하십시오.
  • 가능하면 의미가 드러나는 이름을 사용하십시오(예: fn bare_coverage_attributes() {}).

불안정한 테스트

모든 테스트는 재현 가능하고 신뢰할 수 있도록 노력해야 합니다. 불안정한 테스트는 최악의 테스트이며, 애초에 테스트가 없는 것보다도 나쁘다고 할 수 있습니다.

  • 불안정한 테스트는 전혀 관련 없는 PR에서도 실패할 수 있으며, 이는 다른 기여자를 혼란스럽게 하고 테스트 실패가 관련이 있는지 알아내느라 시간을 낭비하게 만듭니다.
  • 불안정한 테스트는 불안정하고 신뢰할 수 없다는 사실 외에는 테스트 결과로부터 아무런 유용한 정보도 제공하지 않습니다. 테스트가 통과했지만 불안정한 테스트라면, 그저 운이 좋았던 것일까요? 테스트가 불안정한데 실패했다면, 그것은 단지 우연한 실패였을까요?
  • 불안정한 테스트는 테스트 스위트 전체에 대한 신뢰를 떨어뜨립니다. 불안정한 테스트 때문에 테스트 스위트가 무작위로 우연히 실패할 수 있다면, 테스트 스위트 전체가 통과한 것일까요, 아니면 그저 운이 좋았거나 나빴던 것일까요?
  • 불안정한 테스트는 전체 CI에서 무작위로 실패하여 귀중한 자원을 낭비할 수 있습니다.

compiletest 지시문

지시문 목록은 compiletest 지시문을 참조하십시오.

  • ignore-*/needs-*/only-* 지시문을 사용할 때는 이유가 아주 명백한 경우가 아니라면 해당 지시문이 왜 필요한지 간단히 설명하십시오. 예: "//@ ignore-wasi (wasi codegens the main symbol differently)".
  • //@ ignore-auxiliary를 사용할 때는 이 파일을 사용하는 주 테스트 파일을 명시하십시오. 예: //@ ignore-auxiliary (used by `./foo.rs`).

FileCheck 모범 사례

자세한 내용은 LLVM FileCheck 가이드를 참고하십시오.

  • 특정 레지스터 번호나 기본 블록 번호가 특별하거나 테스트에 결정적으로 중요한 경우가 아니라면 이를 매칭하지 마십시오. 적절한 경우에는 패턴을 사용하여 이를 매칭하는 방법을 고려하십시오.

TODO

구체적인 조언은 추후 추가될 예정입니다.