콘텐츠로 이동

Bazel 불안정한 테스트

필수 조건

불안정한 테스트는 동일한 코드로 여러 번 실행할 때마다 다른 결과(통과 또는 실패)를 내는 테스트입니다. 이러한 테스트는 테스트 스위트에 대한 신뢰를 떨어뜨리고, 잘못된 실패를 조사하는 데 개발자의 시간을 낭비하게 만듭니다. Tuist는 불안정한 테스트를 자동으로 감지하고 시간이 지남에 따라 추적할 수 있도록 도와줍니다.

불안정성 감지 방식#

Tuist는 Bazel의 test.xml 리포트에서 개별 케이스를 사용하여 재시도 간, 그리고 지속적 통합(CI)에서 동일한 커밋과 타겟 선택에 대한 실행 간 일관되지 않은 결과를 감지합니다. 로컬 실행은 계속 표시되지만 테스트 케이스를 자동으로 불안정하다고 플래그 지정하지는 않습니다.

테스트 재시도#

재시도는 선택 사항이며 격리와 독립적입니다. --flaky_test_attempts=3는 테스트당 최대 세 번의 Bazel 시도를 활성화하며, 추가 재시도 세 번을 의미하지 않습니다. 기존 재시도 설정을 .bazelrc에 유지하거나 명시적으로 전달하세요:

bash
tuist bazel test -- --flaky_test_attempts=3 //app:tests

Tuist가 결과를 관찰하려면 재시도가 실제로 실행되어야 합니다. Bazel 타겟의 불안정성 요약만으로는 어떤 개별 케이스가 불안정했는지 식별할 수 없습니다.

실행 간 감지#

실행을 비교하려면 커밋 및 브랜치 메타데이터가 필요합니다. 빌드 환경에서 이미 공개하지 않는 경우 이를 제공하세요:

bash
tuist bazel test -- \
--build_metadata=CI=true \
--build_metadata=GIT_COMMIT="$GIT_COMMIT" \
--build_metadata=GIT_BRANCH="$GIT_BRANCH" //app:tests

케이스는 타겟 레이블, 클래스 이름(_suite_ 이름으로 대체), 테스트 이름으로 식별되며, 이는 Bazel 테스트 인사이트에 설명되어 있습니다.

불안정한 테스트 관리#

자동 해제#

탐지와 해제는 프로젝트의 자동화 알림을 통해 실행됩니다. 모든 프로젝트에는 기본 "불안정한 테스트 탐지" 자동화가 제공되며, 이 자동화의 트리거는 테스트를 불안정하다고 표시하고 복구는 테스트가 재트리거 없이 구성된 복구 기간(기본값 14일) 동안 지나면 플래그를 해제합니다. 설정 → 자동화에서 복구 기간을 변경하거나, 복구 작업(예: 테스트 격리 해제)을 수정하거나, 복구를 완전히 비활성화하여 직접 해제할 때까지 테스트가 불안정 상태로 유지되도록 설정할 수 있습니다.

수동 관리#

테스트 케이스 상세 페이지에서 테스트를 수동으로 불안정하다고 표시하거나 표시를 해제할 수도 있습니다. 이는 다음과 같은 경우에 유용합니다:

  • 수정 작업을 진행하면서 이미 알려진 불안정한 테스트를 인지하고 싶을 때
  • 인프라 문제로 인해 테스트가 잘못 표시되었을 때

불안정한 테스트 격리#

격리는 불안정한 테스트를 격리하여 수정하는 동안 CI가 차단되지 않도록 합니다. 기본적으로는 수동 작업입니다: 대시보드의 테스트 케이스 상세 페이지에서 테스트를 격리하고, 해제하며, 모드를 전환합니다. 또한 설정 → 자동화에서 자동화 알림으로 연결하여, 테스트가 불안정성 임계값을 초과하면 자동으로 음소거(또는 건너뛰기)되고, 복구되면 해제되도록 설정할 수 있습니다. 모든 전환(수동 또는 자동)은 테스트 케이스의 감사 로그에 기록됩니다.

기본적으로 복구는 트리거 조건이 더 이상 충족되지 않을 때까지 기다리므로, 이전의 불안정한 실행이 트리거 창을 벗어날 때까지 테스트는 격리된 상태로 유지됩니다. 더 빠르게 복구하려면 복구 시점을 새로운 불안정한 실행 없음으로 설정하세요: 새로운 불안정한 실행 없이 복구 창(일수 또는 실행 횟수)이 지나면 테스트가 복구되며, 새로운 불안정한 실행이 발생할 때마다 대기 시간이 초기화됩니다. 복구 후에는 새로운 불안정한 실행만 테스트를 다시 격리합니다.

tuist bazel test는 각 호출 전에 격리 정책을 가져와서 기본 bazel test 실행에 적용합니다. 일반 bazel test는 여전히 테스트 결과를 보고하지만 격리를 적용하지는 않습니다:

bash
tuist bazel test -- //app:tests

-- 이후의 인수는 bazel test로 전달됩니다. 프로젝트와 작업 디렉터리를 선택하려면 --path를 사용하고, bazelisk와 같은 다른 실행 파일을 선택하려면 --bazel를 사용하세요. --config=ci와 같은 명명된 Bazel 구성은 선택 사항이며 동일하게 작동합니다.

음소거#

주요 격리 워크플로로 음소거를 사용하세요. 음소거된 케이스는 계속 실행되며, 실패는 계속 표시되고 정상인Sibling 케이스는 결과에 여전히 영향을 미칩니다. Tuist는 보고서가 실패한 각 타겟의 모든 실패를 음소거된 케이스에 귀속시킬 때만 Bazel의 테스트 실패 종료 상태를 성공으로 전환합니다. 빌드 오류, 시간 초과, 중단된 실행, 누락되거나 불완전한 리포트, 음소거 집합 외부의 실패는 Bazel의 실패 상태를 유지합니다.

스킵은 Bazel 타겟 단위로 작동합니다. 하나의 케이스를 스킵하면 해당 타겟 전체(정상 케이스 포함)가 제외됩니다. Bazel은 모든 테스트 프레임워크에 대해 개별 케이스를 필터링할 수 없기 때문입니다. 전체 타겟을 제외하려는 경우가 아니라면 음소거를 선호하세요. 명령어는 제외된 모든 타겟 레이블을 출력하므로 빌드 로그에 격리 정책이 무엇을 제외했는지 표시됩니다.

스킵된 타겟이 더 이상 존재하지 않는 경우, Tuist는 경고에서 이를 명시하고 해당 제외 없이 실행합니다. 오래된 케이스를 활성화됨으로 반환하여 정책을 영구적으로 제거하세요. 테스트 타겟이 남아 있지 않으면 Bazel은 정상적인 "테스트를 찾을 수 없음" 종료 상태를 유지합니다.

격리된 테스트가 통과로 표시될 수 있는 이유#

  • 음소거된 테스트는 여전히 실행됩니다. 실패한 음소거 테스트는 테스트 케이스 실행에서 실패로 기록되고 불안정한 것으로 플래그가 지정되지만, 개별 테스트 상태는 재작성되지 않습니다. 재정의되는 것은 전체 테스트 실행입니다: 실행 내의 모든 실패한 테스트 케이스가 음소거되면, 전체 실행이 통과로 보고되므로 음소거된 실패가 CI를 중단시키지 않습니다.
  • 생략된 테스트는 전혀 실행되지 않으므로, 대시보드는 테스트의 마지막 실제 실행 상태를 계속 표시합니다. 해당 스냅샷은 몇 주 전 것일 수 있습니다.

격리된 테스트 다시 실행#

수정을 조사하거나 검증하려면 격리 정책을 우회하세요:

bash
tuist bazel test --no-quarantine -- --nocache_test_results //app:tests

케이스를 활성화됨으로 반환하여 후속 일반 실행에 타겟을 포함시키세요. 스킵된 케이스는 명시적으로 포함될 때까지 새로운 실행을 생성하지 않으므로, 성공적인 새 실행을 기반으로 하는 자동화는 이를 복구하기 전에 검증 실행이 필요합니다.

제한 사항#

  • 명시적인 --build_event_json_file 또는 --target_pattern_file는 활성 격리와 결합할 수 없습니다. 타겟 패턴을 직접 전달하세요.
  • Tuist가 격리 정책을 가져올 수 없는 경우, 명령어는 테스트 실행 전에 중지됩니다. 부분적인 정책을 적용하지 않습니다. 의도적으로 격리 없이 실행하려면 --no-quarantine를 사용하세요.
  • 이전 suite 기반 신원 아래 기록된 음소거와 일치하는 실패는 차단 상태로 유지되며, 명령어는 재적용할 정책을 명시합니다.

기본 동작에 대해서는 Bazel의 테스트 필터, 명령 옵션 및 빌드 이벤트 설명을 참조하세요.

Slack 알림#

Slack 통합에서 불안정한 테스트 알림을 설정하면 테스트가 불안정해질 때 알림을 받을 수 있습니다.

불안정하고 격리된 상태 쿼리하기#

CLI#

tuist test case 명령어 트리는 Tuist가 테스트 케이스에 대해 추적하는 모든 정보를 제공합니다:

bash
tuist test case list --flaky # only flaky test cases
tuist test case list --quarantined # only muted or skipped test cases
tuist test case show <test_case_id> # detail: flakiness rate, last status, run counts
tuist test case events <test_case_id> # audit log: marked_flaky, muted, skipped, ...
tuist test case run list <test_case_id> # run history with status and duration
tuist test case run show <test_case_run_id> # single run, including failure breakdown

이 모든 명령어는 스크립팅을 위해 --json를 지원합니다.

REST API#

동일한 데이터를 HTTP를 통해 사용할 수 있습니다. 전체 경로, 필터 및 응답 필드 목록은 API 참조의 테스트 케이스 엔드포인트를 참조하세요. 테스트 케이스의 상태(불안정 표시 또는 해제, 음소거, 건너뛰기)를 변경하려면 PATCH /api/projects/{account_handle}/{project_handle}/tests/test-cases/{test_case_id}를 is_flaky 또는 state와 함께 전송하세요. 동일한 변경 사항은 tuist test case update 및 update_test_case MCP 도구를 통해서도 가능합니다.