본문으로 건너뛰기
고급약 45분

실패 트리아지 규칙 — 제품 결함·환경 문제·테스트 결함 자동 분류

실패를 제품 결함·환경 문제·테스트 결함으로 자동 분류하는 규칙을 실행 플랫폼 차원에서 설계한다. 한 건의 오류 메시지를 넘어 동시 실패 패턴·블라스트 반경·환경 헬스체크·최초 실패 커밋을 신호로 쓰는 방법, 오분류의 방향별 비용, 사람에게 넘기는 기준, 그리고 분류기 자체를 운영하는 방법을 다룬다.

  • #TestOps
  • #트리아지
  • #실패분류
  • #환경문제
  • #테스트결함
  • #자동화운영

개념

이 레슨의 경계 — 한 건의 메시지에서 한 묶음의 패턴으로

실패 자동 분류는 이 커리큘럼에 이미 두 번 나왔고, 둘 다 실패 한 건 안에서 얻는 신호 를 썼다.

다루는 범위쓰는 신호
m13 레슨 10테스트 프레임워크의 커스텀 리포터실패한 단계(fixture / UI / cleanup)와 오류 메시지 패턴
m18a 레슨 15셀프힐링 래퍼의 판정대체 후보 수와 신뢰도 — 모호하면 치유하지 않고 결함 후보로
m59 레슨 7 — 이 레슨실행 플랫폼의 분류 엔진여러 테스트·여러 실행에 걸친 패턴 + 설비·환경 상태 + 이력

차이를 한 문장으로 쓰면 이렇다. m13 은 "이 실패의 메시지가 무엇을 말하는가"를 묻고, 이 레슨은 "이 실패가 다른 실패들과 함께 무엇을 말하는가" 를 묻는다.

왜 한 단계 올려야 하는지는 예로 보면 분명하다. 메시지만 보면 로케이터 타임아웃인 실패가 300건 동시에 났다. m13 의 규칙은 300건을 모두 "셀렉터 오류"로 분류하고 자동화 담당에게 보낸다. 담당자는 20분을 쓰고 나서야 실제 원인이 "스테이징 애플리케이션이 기동 중이어서 모든 화면이 로딩 스피너였다"는 것을 발견한다. 동시 실패 300건이라는 사실 자체가 가장 강한 신호 였는데, 실패 한 건의 시야에서는 그 신호가 보이지 않는다.

세 범주와 각 범주가 가는 곳

분류 라벨은 세 개로 충분하고, 네 번째는 unknown 이다. 범주를 늘리면 규칙이 복잡해지고 정확도가 떨어진다.

라벨뜻받는 사람이어지는 조치
product-defect제품이 기대와 다르게 동작한다개발팀결함 초안 생성 → 사람 확인 후 등록
env-issue테스트 환경·설비가 정상이 아니다TestOps 당번 / 플랫폼결함 등록하지 않음, 환경 복구 후 재실행, 집계 제외 표시
test-defect테스트 쪽이 틀렸다(기대값·셀렉터·대기·데이터 가정)자동화 담당 / 테스트 소유자테스트 수정 또는 플래키 장부 등록(레슨 4)
unknown신호가 모순되거나 부족하다당번이 직접 본다분류 후 규칙 개선 후보로 기록

범주별로 결함 등록 정책이 다르다 는 점이 중요하다. env-issue 를 결함으로 등록하면 결함 추세가 오염되고, product-defect 를 자동 등록하면 오탐이 그대로 결함 데이터에 들어간다. 자동 분류의 결과는 라우팅에 쓰고, 등록은 사람이 한다.

분류 신호 — 플랫폼만 볼 수 있는 것들

실행 플랫폼은 테스트 한 건보다 많은 것을 안다. 다섯 종류의 신호를 조합한다.

① 블라스트 반경(동시 실패 규모와 분포). 한 실행에서 실패한 테스트의 비율과 분포가 가장 강한 신호다.

동시 실패 비율과 분포로 보는 1차 판정
 
실패 비율 30% 이상, 여러 기능 영역에 고르게 퍼짐
  → env-issue 강한 후보 (환경·설비·공용 데이터)
 
실패가 한 기능 영역(예: 결제)에 몰림
  → product-defect 또는 그 영역의 테스트 결함
 
실패 1~2건, 산발적, 과거에도 갈린 이력 있음
  → test-defect / 플래키 (레슨 4의 장부 확인)
 
실패 비율 100%, 첫 테스트부터 전부
  → env-issue 거의 확정 (프리플라이트가 놓친 경우)

② 환경 헬스체크 결과. 레슨 3의 프리플라이트와, 실행 중 주기적으로 찍는 헬스 스냅샷을 쓴다. 실패 시각과 의존 서비스 비정상 구간이 겹치면 env-issue 가 거의 확정된다. 이 신호가 있으면 오류 메시지를 읽을 필요가 없어진다.

③ 환경 좌표 변화. 직전 성공 실행과 이번 실패 실행의 좌표(레슨 3)를 비교한다. 스키마 head 가 바뀌었다면 마이그레이션 관련, 시드 세트가 바뀌었다면 기준 데이터 관련, 플래그가 바뀌었다면 구성 관련 — 각각 다른 담당에게 간다. 좌표가 동일한데 결과가 갈렸다면 그건 정의상 플래키다.

④ 최초 실패 커밋. 같은 테스트의 이력에서 통과→실패로 바뀐 경계 커밋을 찾는다. 경계 커밋이 제품 코드만 건드렸다면 product-defect 후보, 테스트 코드만 건드렸다면 test-defect 후보다. 둘 다 건드렸으면 unknown 으로 두고 사람에게 넘긴다. 이 신호는 레슨 6의 커밋-결과 연계가 있어야 계산할 수 있다.

⑤ 설비 신호. 러너의 CPU·메모리 포화, 그리드 세션 대기 급증, 디스크 부족, 단말 설치 실패(레슨 2). 이 신호가 있으면 타임아웃 계열 실패는 env-issue 로 보내야 한다. 설비 포화 상태의 타임아웃을 test-defect 로 보내는 것이 실무에서 가장 흔한 오분류다.

여기에 m13 레슨 10의 단계·메시지 신호 를 6번째로 더한다. 플랫폼 차원의 신호가 모두 중립일 때 마지막으로 보는 것이 메시지다 — 순서가 거꾸로 되면 위의 300건 사례가 반복된다.

규칙의 순서 — 넓은 신호부터 좁은 신호로

분류 규칙은 평가 순서가 결과를 결정한다. 범위가 넓은 신호를 먼저 본다.

트리아지 규칙 (평가 순서대로)
 
R1. 프리플라이트 실패 또는 실행 중 의존 서비스 비정상 구간과 겹침
    → env-issue (신뢰도 높음). 결함 등록 금지, 집계 제외, 당번 알림.
 
R2. 실행 전체 실패 비율이 30% 이상이고 여러 기능 영역에 분산
    → env-issue (신뢰도 중간). 당번이 환경 확인 후 확정하거나 R6 로 내린다.
 
R3. 설비 포화 신호(러너 자원·세션 대기·디스크) 가 실패 시각과 겹침
    → env-issue (신뢰도 중간). 실패 유형이 타임아웃 계열일 때만 적용.
 
R4. 해당 테스트가 플래키 장부에 '관찰중' 또는 '격리' 상태
    → test-defect / 플래키로 라우팅. 게이트 차단하지 않음(레슨 4).
 
R5. 최초 실패 커밋이 식별되고 그 커밋이 한쪽만 변경
    제품 코드만 → product-defect 후보 / 테스트 코드만 → test-defect 후보
 
R6. 위가 모두 중립이면 단계·메시지 신호(m13 레슨 10의 분류기)를 적용
    fixture 단계 실패 → env-issue
    로케이터 타임아웃·strict 위반 → test-defect 후보
    단언 실패 → product-defect 후보
 
R7. 신호가 서로 모순되거나 R1~R6 중 어느 것도 걸리지 않음
    → unknown. 당번 큐로 보내고, 사람의 최종 분류를 규칙 개선 입력으로 기록한다.

R6 이 마지막에 오는 것이 이 레슨의 핵심이다. 메시지는 가장 구체적이지만 가장 좁은 증거이고, 좁은 증거를 먼저 보면 넓은 원인을 놓친다.

규칙마다 신뢰도를 명시 하는 것도 중요하다. 신뢰도가 높은 규칙(R1)은 자동으로 확정하고, 중간인 규칙(R2·R3)은 라우팅만 하고 확정은 사람이 한다. 모든 규칙을 확정으로 다루면 오분류가 조용히 쌓인다.

오분류의 대가 — 방향마다 비용이 다르다

자동 분류의 설계는 정확도 최적화가 아니라 비용 비대칭 설계 다. 오분류 여섯 방향의 비용이 전부 다르다.

실제 → 분류무슨 일이 벌어지는가비용
제품 결함 → 환경 문제결함이 등록되지 않고 재실행 대상이 된다. 환경 복구 후에도 실패하면 발견되지만, 그 사이 배포가 나갈 수 있다가장 크다 — 결함 유출
제품 결함 → 테스트 결함자동화 담당이 테스트를 "고치려" 하다가 기대값을 제품에 맞춰 바꾼다. 결함이 영구히 숨는다매우 크다 — 은폐
환경 문제 → 제품 결함개발팀에 오탐 결함이 간다. 신뢰가 깎이고, 반복되면 자동화 결함을 전부 무시하게 된다중간 — 신뢰 손실
환경 문제 → 테스트 결함자동화 담당이 멀쩡한 테스트를 들여다본다. 시간 낭비작다
테스트 결함 → 제품 결함개발팀이 조사하고 "제품 정상"으로 반송한다. 왕복 비용중간
테스트 결함 → 환경 문제재실행하고 또 실패한다. 플래키로 쌓이고 원인이 안 밝혀진다중간

첫 두 줄이 나머지보다 훨씬 비싸다. 여기서 설계 원칙이 나온다.

의심스러우면 product-defect 쪽으로 기울인다. 오탐 결함의 비용(개발팀의 조사 시간)은 결함 유출의 비용보다 작다.

구체적으로는 두 가지 장치가 된다. 첫째, 단언 실패는 다른 신호가 명확히 반대하지 않는 한 product-defect 후보로 둔다. 둘째, env-issue 로 분류한 건은 환경 복구 후 반드시 재실행하고, 재실행에서도 실패하면 자동으로 product-defect 후보로 승격한다. 이 승격 규칙이 없으면 env-issue 가 결함의 무덤이 된다 — 레슨 4의 격리가 쓰레기통이 되는 것과 같은 구조다.

env-issue 승격 규칙
1. env-issue 로 분류 → 환경 복구 후 24시간 안에 같은 좌표에서 재실행
2. 재실행 통과 → env-issue 확정, 종결
3. 재실행 실패 → 라벨을 unknown 으로 올리고 당번 큐로. 자동 종결 금지
4. 재실행이 24시간 안에 일어나지 않음 → 당번 큐로 (방치 방지)

사람에게 넘기는 기준

자동 분류의 목표는 100%가 아니다. 목표는 사람이 봐야 하는 건수를 감당 가능한 수준으로 줄이는 것 이고, 어디까지 자동으로 할지는 명시적으로 정한다.

사람에게 넘기는 조건 (하나라도 해당하면 당번 큐)
- 라벨이 unknown
- 신뢰도 '중간' 규칙으로 분류되었고, 라벨이 env-issue 이며 블라스트 반경이 50% 이상
  (대량 실패를 자동 종결하지 않는다)
- product-defect 후보 — 결함 등록은 항상 사람이 한다
- env-issue 재실행에서 또 실패
- 동일 테스트가 7일 안에 서로 다른 라벨로 3회 이상 분류됨 (규칙이 흔들린다는 신호)
- 릴리스 판정 대상 실행(레슨 6의 증거에 들어가는 실행)의 모든 실패

마지막 줄이 실용적으로 중요하다. 평상시 실행은 자동 분류에 맡기되, 릴리스 증거가 되는 실행은 전수 사람 확인 을 거친다. 판정에 쓰이는 데이터의 품질 기준을 평상시보다 높게 두는 것이다.

분류기 자체를 운영한다

분류 규칙은 만들고 끝나는 코드가 아니다. 세 가지가 필요하다.

① 분류기의 회귀 시험. 각 라벨을 일부러 만드는 샘플 실패를 고정해 두고, 규칙을 바꿀 때마다 그 샘플들이 기대 라벨로 분류되는지 확인한다. m13 레슨 10이 지적한 "메시지 형식 의존" 문제가 플랫폼 차원에서도 그대로 적용된다 — 도구 버전을 올리면 메시지가 바뀌고, 바뀐 메시지는 조용히 unknown 을 늘린다.

② 정확도 측정. 사람이 최종 분류한 결과를 정답으로 두고, 자동 라벨과 비교한다. 전체 정확도 하나가 아니라 방향별 오분류 건수 를 본다 — 비용이 다르기 때문이다. "제품 결함을 환경 문제로 보낸 건수"는 0 을 목표로 두고, 나머지는 추세만 본다.

③ unknown 비율 추세. 이 비율이 올라가면 규칙이 현실과 멀어지고 있다는 신호다. 레슨 5의 지표 중 트리아지 소요 시간과 함께 보면, 분류 체계가 건강한지 한눈에 보인다.

분류기 건강 지표 (주간)
- unknown 비율 — 목표: 전체 실패의 15% 이하
- 방향별 오분류 — 제품→환경, 제품→테스트: 목표 0건
- 사람 재분류율 — 자동 라벨이 사람에 의해 뒤집힌 비율
- 트리아지 중위 소요 시간 (레슨 5의 ⑥)

실무에서 왜 필요한가

트리아지는 TestOps 의 일 중 사람 시간을 가장 많이 먹는 항목이다. 실행당 실패 10건, 하루 8회 실행, 건당 분류 5분이면 하루 6시간 이상이 분류에만 든다. 이 시간은 테스트를 늘릴수록 선형으로 늘어나고, 어느 지점에서 자동화를 늘리지 못하게 만드는 상한 이 된다. 분류의 70%를 규칙으로 처리하면 그 상한이 세 배로 올라간다.

분류가 없을 때의 2차 효과가 더 크다. 분류되지 않은 실패는 "일단 재실행"으로 처리되고, 재실행으로 넘어간 실패는 추적되지 않는다. 그 상태가 몇 달 지나면 실패 데이터 전체가 무의미해지고, 레슨 5의 지표도 레슨 6의 증거도 믿을 수 없게 된다. 트리아지는 뒤의 모든 데이터의 품질을 결정하는 입구 다.

조직 관계에도 작용한다. 환경 문제를 결함으로 등록해 개발팀에 보내는 일이 반복되면, 개발팀은 QA 가 보내는 결함을 전부 의심하기 시작한다. 반대로 분류가 정확하면 개발팀에 가는 결함은 "조사할 가치가 있는 것"으로 신뢰받는다. 이 신뢰가 자동화가 실제로 품질에 기여하는지를 가른다.

실습 과제

과제 1 — 지난 실패 50건을 다시 분류하기 (35분)

최근 실패 50건을 모아, 본문의 R1~R7 순서로 수동 적용해 라벨을 매긴다. 각 건마다 어느 규칙에서 멈췄는지 기록한다.

  • R6(메시지 신호)까지 내려간 건은 몇 %인가 — 플랫폼 신호로 먼저 걸리는 비율을 본다
  • 실제 원인(사후에 알게 된 것)과 비교해 방향별 오분류 건수를 센다
  • "제품 결함 → 환경 문제" 또는 "제품 결함 → 테스트 결함" 방향의 오분류가 있었는가. 있다면 그 건이 발견되기까지 며칠이 걸렸는지 적는다

과제 2 — 우리 신호 가용성 점검과 규칙 작성 (30분)

본문의 다섯 신호(블라스트 반경·헬스체크·좌표 변화·최초 실패 커밋·설비 신호)에 대해 현재 수집 여부를 표로 정리한다.

  • 수집하지 않는 신호가 있으면 수집 비용과 예상 효과를 적는다
  • 가용한 신호만으로 R1~R7 을 우리 버전으로 다시 쓴다. 쓸 수 없는 규칙은 지우고, 지운 자리를 어떻게 메울지 적는다
  • 각 규칙에 신뢰도(높음/중간)를 붙이고, 자동 확정할 규칙과 라우팅만 할 규칙을 가른다

과제 3 — 승격·에스컬레이션 규칙과 분류기 회귀 샘플 (25분)

두 가지를 작성한다.

  1. env-issue 승격 규칙 — 재실행 시한, 재실행 실패 시 처리, 재실행이 일어나지 않을 때의 처리. 그리고 사람에게 넘기는 조건 목록을 우리 상황으로 고쳐 쓴다.
  2. 분류기 회귀 샘플 — 각 라벨마다 대표 실패 사례를 2건씩, 총 6~8건의 샘플을 고정한다. 각 샘플에 기대 라벨과 어느 규칙에서 걸려야 하는지를 적는다.

마지막으로 분류기 건강 지표 네 개의 현재값을 측정하거나, 측정할 수 없으면 무엇이 없어서인지 적는다.

자가 체크리스트

  • m13 레슨 10(메시지·단계 신호)과 이 레슨(플랫폼 신호)의 차이를 설명할 수 있다
  • m18a 레슨 15의 신뢰도 기반 결함 후보 판정이 어느 지점에서 이 규칙과 만나는지 안다
  • 라벨을 세 개 + unknown 으로 유지하고, 라벨별 결함 등록 정책이 다르게 정해져 있다
  • 블라스트 반경을 1차 신호로 쓰고 있어 대량 실패를 셀렉터 오류로 보내지 않는다
  • 프리플라이트·헬스 스냅샷 결과를 실패 시각과 대조할 수 있다
  • 직전 성공 실행과 환경 좌표를 비교해 변화 축을 찾을 수 있다
  • 규칙의 평가 순서가 넓은 신호 → 좁은 신호로 되어 있다
  • 오분류 여섯 방향의 비용 차이를 알고, 의심스러울 때 제품 결함 쪽으로 기울인다
  • env-issue 가 재실행 없이 자동 종결되지 않고, 재실패 시 승격되는 규칙이 있다
  • 사람에게 넘기는 조건이 명시되어 있고, 릴리스 증거가 되는 실행은 전수 확인한다
  • 분류기 회귀 샘플이 있고, unknown 비율과 방향별 오분류를 주기적으로 본다

흔한 실수

오류 메시지부터 본다. 가장 흔하고, 300건 동시 실패를 셀렉터 오류로 분류하는 결과를 만든다. 메시지는 마지막 증거다. 블라스트 반경을 먼저 보는 순서만 바꿔도 분류 품질이 크게 올라간다.

env-issue 를 자동으로 종결한다. 환경 문제로 분류하고 재실행 확인 없이 닫으면, 제품 결함이 그 라벨 아래 묻힌다. 격리가 쓰레기통이 되는 것과 같은 구조이고, 결과는 더 나쁘다 — 결함 유출이다.

설비 포화 상태의 타임아웃을 테스트 결함으로 보낸다. 자동화 담당은 멀쩡한 테스트를 들여다보며 시간을 쓰고, 원인은 러너 메모리에 있다. 병렬 수를 올린 직후의 실패는 설비 신호를 먼저 확인한다.

분류 결과로 결함을 자동 등록한다. 오탐이 결함 데이터에 그대로 들어가 결함 추세가 오염되고, 개발팀의 신뢰가 깎인다. 자동 분류는 라우팅까지, 등록은 사람이 한다.

라벨을 계속 늘린다. "셀렉터 오류", "타임아웃", "데이터 문제", "써드파티" 같은 하위 라벨을 늘리면 규칙이 서로 겹치고 unknown 이 줄지 않는다. 세 개로 라우팅하고, 세부는 티켓 본문에 쓴다.

분류기를 만들고 방치한다. 도구 버전이 올라가면 메시지가 바뀌고 규칙이 조용히 빗나간다. 회귀 샘플과 unknown 비율 추세가 없으면 빗나간 사실을 몇 달 뒤에 안다.

참고 자료

  • ISTQB Foundation Level v4.0 실러버스 — 결함 보고와 테스트 결과 분석 절
  • ISTQB CTAL-TAE v2.0 실러버스 — 자동화 결과 분석과 실패 원인 분류 장. 장 번호는 원문 확인
  • Google Testing Blog — 대규모 CI 에서 실패 원인을 자동 분류·집계한 사례 묶음. 개별 글 제목과 게시 시점은 원문 확인
  • Playwright·JUnit·pytest 의 리포터 API 문서 — 실패 메타데이터로 노출되는 필드. 필드 이름은 버전마다 바뀌므로 원문 확인
  • 분류 성능 평가의 기본 개념(혼동 행렬, 비용 민감 분류) 입문 자료 — 방향별 비용 비대칭을 다루는 틀
  • 이 커리큘럼 안의 관련 레슨: 모듈 13 레슨 10(단계·메시지 기반 1차 분류), 모듈 18a 레슨 15(셀프힐링의 결함 후보 판정), 모듈 14 레슨 5(False Alarm), 이 모듈 레슨 2(설비 신호)·레슨 3(프리플라이트·좌표)·레슨 4(플래키 장부)·레슨 5(트리아지 소요 지표)·레슨 6(릴리스 증거)

낯선 말 풀이

이 레슨에 나온 약어입니다. 본문에서도 처음 나올 때 점선으로 표시해 두었습니다 (제목과 링크 글자는 그대로 둡니다).

UI — 사용자 인터페이스
사람이 직접 보고 누르는 부분 — 화면, 버튼, 입력창.
CPU — 중앙처리장치
계산을 담당하는 부품. 사람으로 치면 머리다.
QA — 품질보증
만든 것이 쓸 만한지 확인하고, 애초에 덜 망가지게 만드는 방법을 정하는 일. "테스트"는 그 일의 일부다.
ISTQB — 국제 소프트웨어 테스팅 자격 위원회
테스터 자격 시험을 만들고 용어를 정리하는 국제 단체.
CTAL-TAE — 상급 자격 · 테스트 자동화
상급 테스터 자격 중 자동화 설계를 다루는 과목.
CI — 지속적 통합
코드를 올릴 때마다 자동으로 합쳐서 빌드하고 시험까지 돌리는 방식.
JUnit — 제이유닛
자바로 만든 프로그램의 단위 시험을 쓰고 돌리는 가장 널리 쓰이는 도구.
API — 응용 프로그램 인터페이스
프로그램끼리 주고받는 창구. 사람이 화면 버튼을 누르는 대신, 프로그램이 정해진 주소로 요청을 보내 답을 받는다.

용어집 전체 보기