테스트 커버리지 80%인데 배포가 무서운 이유
테스트 수가 늘어도 신뢰가 오히려 줄어드는 flaky·false positive 문제 정리
커버리지 숫자가 거짓말하는 방식
테스트 600개. 커버리지 82%. 근데 배포 전날 밤 여전히 손이 떨린다.
막상 들여다보면 이유가 보인다.
- 테스트가 통과해도 아무도 그 결과를 믿지 않는다
- “한 번 더 돌려봐” 가 팀 문화로 굳어진 상태
- flaky 가 3개면 전체 suite 의 신뢰도가 같이 무너진다
비율 문제가 아니다. 1개의 flaky 가 599개의 green 을 희석시킨다. 사람은 패턴이 아니라 예외를 기억하니까.
Flaky 와 False Positive 는 다른 병이다
헷갈리기 쉬운데 원인과 처방이 다르다.
Flaky test
- 같은 코드, 다른 결과
- 원인: 타이밍, 외부 의존, 공유 상태, 순서 의존
- 증상: CI 재실행하면 통과
- 처방: 격리. 타임아웃 고정. 외부 호출 mock.
False positive
- 코드가 망가졌는데 테스트는 green
- 원인: assertion 이 너무 약함.
assert response is not None류 - 증상: 프로덕션 버그 → 테스트 기록 확인 → 해당 테스트 통과 이력만 있음
- 처방: 구체적인 값 검증. 경계 케이스. mutation testing 으로 assertion 강도 측정.
보통은 flaky 만 잡으면 된다고 생각한다. 막상 해보면 false positive 가 훨씬 조용하고 훨씬 위험하다. flaky 는 시끄럽게 드러나지만 false positive 는 배포 후에야 모습을 드러낸다.
우리가 실제로 한 것
올해 기준으로 효과 있었던 것만 적는다.
- flaky 목록을 별도 레이블로 격리 (
@pytest.mark.flaky). CI block 에서 제외, 주간 리포트에만 포함. - 격리한 순간부터 “재실행” 문화가 사라졌다. 체감 신뢰도가 먼저 올랐고, 실제 flaky 수는 6주 후에 줄었다.
- assertion 리뷰를 PR 체크리스트에 한 줄 추가. “이 assert 가 구현 버그를 잡을 수 있나?”
- mutation testing (mutmut) 은 전체 suite 에 돌리면 너무 느림. 핵심 도메인 모듈 3개에만 주 1회 CI 별도 job.
숫자: flaky 격리 후 2주 만에 “배포 전 재실행” 횟수 팀 평균 4.2회 → 0.3회.
다음 한 가지
다음 글 시작에 한 줄 먼저: mutation score 를 CI 대시보드에 붙이기로 했는데, 진짜 붙였나.
🛒 이 글과 어울리는 추천 상품
위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.