테스트가 늘어도 신뢰가 줄어드는 이유
flaky test 와 false positive 가 팀의 테스트 신뢰를 어떻게 무너뜨리는가
테스트 커버리지 숫자는 올라가는데, CI 가 빨간불이어도 아무도 멈추지 않는 팀이 있다. 그 팀이 나쁜 게 아니다. 테스트가 먼저 팀을 배신한 거다.
어떻게 신뢰가 깎이나
처음엔 작은 균열이다. 어떤 테스트가 월요일 아침에 이유 없이 실패한다. 재실행하면 통과. 다음 주에 또. “flaky 하네” 하고 넘긴다. 두 달 뒤엔 그 테스트가 5개가 돼 있고, 팀원들은 CI 빨간불을 보면 실패 로그 대신 재실행 버튼을 먼저 누른다.
이게 습관으로 굳으면 진짜 버그가 통과된다. 실제로 올해 초 우리 팀에서 결제 관련 로직에 엣지 케이스가 있었는데, 해당 테스트가 flaky 하다는 인식이 팀 내에 퍼져 있어서 실패 신호를 두 번이나 묵살했다. 세 번째에야 “이번엔 진짜인가?” 하고 들여다봤다. 실제 버그였다.
False positive 는 방향이 반대라서 더 교묘하다. 테스트가 통과했는데 프로덕션에서 터진다. mock 을 너무 촘촘하게 쌓아서, 실제 외부 API 응답 스펙이 바뀌었는데 테스트가 전혀 감지 못 한 경우다. 이런 게 두어 번 반복되면 팀원들 머릿속에 “어차피 테스트 통과해도 모른다” 가 박힌다. 커버리지 80% 찍어도 배포 전날 수동 확인을 더 믿게 된다.
결국 신뢰 하락은 테스트 수와 반비례할 수 있다. 불확실한 테스트가 많을수록 신호 대 잡음 비가 나빠진다.
막상 고쳐보면 생각보다 단순한 원인들
Flaky 테스트를 추적해보면 원인이 몇 가지로 수렴된다.
- 시간 의존성:
datetime.now()를 테스트 내부에서 직접 쓰거나, sleep 으로 비동기 처리를 기다리는 패턴. 슬로우 CI 환경에서 타이밍이 안 맞으면 터진다. 픽스는 간단하다. 시간을 주입받도록 바꾸거나, sleep 대신 명시적 wait 조건을 쓴다. - 공유 상태: 테스트 간에 DB 픽스처나 전역 변수를 공유하면, 실행 순서에 따라 결과가 달라진다. 우리 팀은 한동안 pytest 의
autousefixture 로 세션 스코프 DB를 공유했는데, 병렬 실행 도입하자마자 flaky 가 폭발했다. 각 테스트가 독립된 트랜잭션 안에서 돌고 롤백하도록 바꿨더니 절반 이상 잡혔다. - 외부 의존성 mock 의 과신: mock 은 인터페이스 계약을 고정시키는 도구인데, 계약 자체가 바뀌어도 mock 은 모른다. contract test 혹은 최소한 통합 테스트 레이어를 분리해서 실제 응답을 주기적으로 검증하는 게 필요하다.
False positive 쪽은 조금 다르게 접근했다. 테스트가 “무엇을 검증하는가” 를 명시적으로 적도록 팀 컨벤션을 바꿨다. 함수 이름을 test_payment_success 에서 test_payment_returns_201_when_card_approved 식으로. 쓰다 보면 “이 테스트가 실제로 카드 승인 경로를 타고 있나?” 를 자연스럽게 되묻게 된다. mock 이 실제 경로를 우회하고 있다면 그 질문에서 걸린다.
다음 한 가지
Flaky 테스트를 발견하면 그 자리에서 격리하거나 삭제한다 — “나중에 고치자” 는 팀 신뢰를 조금씩 갉아먹는 기술 부채 중 가장 눈에 안 띄는 종류다.
🛒 이 글과 어울리는 추천 상품
위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.