LabHub

CI/CD 파이프라인 · 테스트 게이트 · 이론

게이트는 '막는 기준'을 정하는 일이다

LabHub 에서 이어서 보기

한 줄 요약

테스트 게이트의 본질은 테스트를 많이 돌리는 게 아니라, 어떤 신호가 나왔을 때 병합을 막을지 미리 합의하고 그 판정을 기계가 대신하게 만드는 일이다.

왜 이게 필요했나

결함은 늦게 잡을수록 비싸진다. IBM 연구로 널리 인용되는 배수는 개발 단계 1, QA 10, 프로덕션 100 이상이다. 같은 버그라도 내 브랜치에서 잡으면 30분이면 끝나지만, 프로덕션에서 잡으면 장애 대응·핫픽스·회고·고객 커뮤니케이션까지 붙는다. 게이트는 이 비용 곡선의 왼쪽 끝에서 잡으려고 두는 장치다.

문제는 어떤 테스트를 얼마나 두느냐다. 테스트 피라미드의 권장 비율은 유닛 70 / 통합 20 / E2E 10 이다. 이게 뒤집힌 역피라미드(아이스크림 콘)가 되면 네 가지가 한꺼번에 온다. E2E 는 느려 피드백 루프가 길어지고, 플레이키가 빈번하며, 실패해도 어디가 원인인지 파악이 어렵고, 유지보수 비용이 기하급수적으로 는다. 테스트가 많아졌는데 아무도 결과를 믿지 않는 상태가 바로 이 모양이다.

어떻게 동작하나

게이트는 세 부분으로 나뉜다.

첫째, 판정 기준. 커버리지는 핵심 비즈니스 로직 80% 이상, 전체 60~80% 를 목표로 잡되, 100% 커버리지보다 의미 있는 assertion 을 가진 테스트가 더 중요하다는 원칙을 잊으면 안 된다. 숫자만 맞추는 테스트는 커버리지 리포트만 예쁘게 만들고 버그는 그대로 통과시킨다.

둘째, 차단 정책. 유닛과 통합은 반드시 차단한다. E2E 는 주요 흐름만 차단하고 나머지는 관찰로 둔다. 성능은 임계치를 넘을 때만, 보안 스캔은 CRITICAL 만 차단한다. 카오스 테스트는 비차단으로 두고 지표만 본다. 전부 차단으로 걸면 사람들이 게이트를 우회하는 방법을 먼저 배운다.

셋째, 강제 지점. 게이트가 실제로 강제되는 곳은 파이프라인 스크립트가 아니라 브랜치 보호의 required status checks 다. 스크립트는 결과만 만들고, 병합을 막는 권한은 저장소 설정이 갖는다. IaC 쪽에도 같은 판이 있다. Plan 은 PR 에서 보여 주고 Apply 는 merge 후 자동 실행한다.

플레이키 테스트는 게이트의 신뢰를 갉아먹는 주범이라 따로 다뤄야 한다. 고정 sleep 대신 특정 조건을 기다리는 명시적 대기를 쓰고, 테스트 간 의존성을 끊고, 네트워크는 모킹하거나 상한이 있는 재시도로 감싸고, 날짜 같은 동적 데이터는 고정한다. 재시도는 반드시 상한이 있어야 한다. 무한 재시도는 안정화가 아니라 실패를 감추는 것이다. 그래도 흔들리는 테스트는 격리 목록에 넣어 병합을 막지 않게 하되, 격리됐다는 사실을 리포트에 남겨 잊히지 않게 한다.

현장에서 만나는 모습

게이트를 처음 켜면 반드시 "지금 당장 급한데 이것 때문에 못 나간다"는 요청이 온다. 그때 필요한 건 예외 승인 절차이지 게이트를 끄는 스위치가 아니다. 또 하나 자주 보는 장면은 실패한 테스트를 고치는 대신 재시도 횟수를 늘리는 것이다. 재시도 횟수는 늘어나는데 실패율은 그대로라면, 그 테스트는 이미 신호가 아니라 소음이다.

다음 실습에서 할 것

테스트 러너와 커버리지 게이트, 재시도, 격리를 셸로 직접 만든다. 실패해도 나머지를 끝까지 돌려 전체 그림을 보여 주는 러너, 경계값에서 정확히 판정하는 커버리지 게이트, 상한이 있는 재시도, 그리고 수치와 판정이 일치하는 JSON 리포트를 만들어 본다.