5.7.4. 테스트 케이스의 생명주기 관리 체계 구축 및 부실 테스트(Flaky Test)의 무자비한 제거
모든 소프트웨어 코드에 수명이 있듯, 결정론적 오라클의 채점 기준이 되는 절대 진리인 ’골든 샘플(Golden Sample)’로 지정된 테스트 픽스처(Fixture) 데이터셋 역시 결코 영원히 유효할 수는 없다.
특히 변화무쌍한 에이전틱(Agentic) AI 파이프라인에서, 테스트 케이스 코드는 급변하는 비즈니스 정책의 변경과 정기적인 기저 파운데이션 모델(Foundation Model)의 가중치 업데이트(예: GPT-4 Turbo에서 GPT-4o로의 마이그레이션)라는 거센 외풍을 항상 정면으로 맞을 수밖에 없다.
어제 퇴근하기 전까지만 해도 MLOps 파이프라인(CI/CD)에서 완벽히 초록색으로 100% 통과(Pass)하던 테스트가, 오늘 출근해서 빌드해보니 갑자기 붉은색 실패(Fail)를 띄우고, 찝찝해서 재실행(Retry) 버튼을 한 번 눌러봤더니 이내 다시 초록색 성공(Pass)으로 둔갑하며 돌아오는 기괴한 현상.
우리는 소프트웨어 공학에서 이러한 재현 불가능한 간헐적 테스트 실패를 **‘부실 테스트(Flaky Test)’**라고 부르며, 이는 결정론적 오라클 시스템의 신뢰성을 엔지니어들의 내면에서부터 조용히 갉아먹는 가장 치명적이고 악성적인 암세포(Cancer) 질병이다.
1. 부실 테스트(Flaky Test)가 AI 파이프라인 신뢰도에 미치는 참혹한 해악
Flaky Test는 백엔드 로직의 명확한 버그가 아니라, 주로 확률적 언어 모델 특유의 ’비결정성(Nondeterminism)’이 오라클의 헐렁한 방어망 틈새를 비집고 새어 나올 때 파이프라인을 붉게 물들인다.
- [유의어/동의어 환각 엣지 케이스]: 오라클 코드가 파이썬으로 무식하게
assert "환불" in llm_response.text를 기대하고 문자열을 긁었는데, 모델이 Temperature 확률 분포에 따라 오늘 아침 우연히 “결제 취소“라는 완벽한 동의어를 선택하여 뱉어버렸을 때 발생한다. - [포맷 경계의 미세한 파괴 (Boundary Instability)]: JSON을 완벽하게 잘 반환하던 모델이 특정 컨텍스트 페이로드에서 우연히 10번에 1번 꼴로 응답 끝에 트레일링 콤마(Trailing Comma) 하나를 더 찍거나, 마크다운 백틱(
```) 하나를 누락하여 정규식 파서(Parser)를 터뜨리는 경우다.
바쁘고 지친 개발자들과 QA 팀이 이러한 간헐적인 Flaky Test 실패를 *“아, 그건 회귀 버그가 아니라 그냥 오늘따라 AI가 가끔 실수하는(Hallucinate) 거니까 무시하세요”*라고 치부하기 시작하고, CI/CD 봇의 Fail 알람을 강제로 통과 강행(Force Merge/Skip)시키기 시작하면, 엔터프라이즈의 테스트 스위트 전체에 대한 위대한 신뢰도가 순식간에 모래성처럼 무너진다.
나중에는 진짜 치명적인 프롬프트 인젝션(Prompt Injection) 해킹 공격이 버그로 침투하여 파이프라인이 붕괴되어도, 사람들은 “어차피 또 그 망할 AI Flaky Test가 뜬 거겠지“라며 늑대가 나타났다는 보안 경고를 무시하게 되는 **‘양치기 소년 증후군(The Boy Who Cried Wolf Syndrome)’**에 빠져 시스템 전체가 파국을 맞이한다.
2. 테스트 케이스의 4단계 생명주기(Lifecycle) 거버넌스
이러한 Flaky Test 곰팡이를 사내 코드베이스에서 무자비하게 색출하고 테스트 오라클의 절대적 순도를 높이기 위해, 모든 골든 샘플 픽스처(Fixture) 예제들은 반드시 다음과 같은 4단계의 엄격한 MLOps 생명주기 상태(State) 태그를 달고 버저닝(Versioning) 관리되어야만 한다.
- [Draft (초안 / 관찰 단계)]: 운영 로그(Production Log) 마이닝을 통해 새롭게 발굴된 예비 픽스처 데이터. 아직 CI 파이프라인의 배포를 멈출(Blocking) 권한이 없으며, 백그라운드 섀도우 모드(Shadow Mode)에서 신뢰성을 테스트하며 모델 교체 시의 참고 지표(Telemetry) 자료로만 조용히 활용된다.
- [Active (활성 / 절대 권력)]: 최근 1개월간 100회의 CI/CD 야간 런타임(Nightly Build) 실행에서 단 한 번의 오차도 없이 100%의 통과율을 보인 순도 99.9%의 진정한 골든 샘플. 이 범주의 테스트가 단 하나라도 실패하면, 전체 인프라 파이프라인의 라이브 배포 프로세스를 즉시 셧다운(Blocking) 시켜버리는 막강한 검증 권한을 가진다.
- [Quarantine (격리 / 병동 수용)]: Active 상태의 통과율 100% 테스트가 어느 날 100회 중 단 1번이라도 Flaky한 붉은색 간헐적 실패(Intermittent Fail)가 감지된다면, 그 테스트 케이스는 그 즉시 권한을 박탈당하고 파이프라인 차단 권한이 없는 ‘격리 병동(Quarantine)’ 상태로 좌천 강등된다. 파이프라인의 배포를 멈추지는 않지만, 매일 아침 출근하는 AI 개발팀의 슬랙(Slack) 디버깅 대시보드 정중앙에 ’원인 규명이 필요한 최우선 부채 과제’로 붉게 노출된다.
- [Retired (폐기 / 무덤)]: 사내 비즈니스 로직(예: 30일 이내 환불 불가 정책 변경)이 완전히 뒤바뀌었거나, 사용자 트래픽 패턴이 바뀌어 더 이상 발생하지 않는 낡은 유스케이스 코너 케이스로 판명되어 공식적으로 퇴역하고 삭제 처리된 데이터 폴더.
3. 격리 병동(Quarantined)에 수용된 부실 테스트의 치료 및 리팩토링 전략
격리 병동으로 강등된 테스트 케이스의 원인을 외과 수술처럼 뜯어고쳐, 다시 절대 권한을 가진 Active 상태로 복귀시키는 치열한 디버깅 작업이야말로 시니어 프롬프트 엔지니어링과 아키텍처 오라클 설계의 진정한 공학적 정수(Essence)다.
이를 고치기 위한 전략은 양극단으로 나뉜다.
- [전략 1. 오라클의 잣대 완화 (Relaxing Oracle Constraints)]:
“결제 취소“와 “환불“이라는 단어를 모델이 Temperature를 타며 번갈아 쓰는 게 문제의 원인이라면, 모델을 탓할 것이 아니라 쪼잔하게 코드를 짠 인간의 오라클을 탓해야 한다. 오라클 로직을assert any(k in llm_response.text for k in ["환불", "결제 취소", "청약 철회"])와 같이 동의어 허용 집합(Synonym SET) 목록을 유연하고 관대하게 포용하도록 스키마를 동적으로 확장해야 한다. - [전략 2. 프롬프트 시스템 규제선의 잔혹한 강화 (Tightening Prompt Rules)]:
만약 모델의 변덕으로 반환되는 마크다운 JSON 포맷 껍데기가 10번 중 1번 확률로 자꾸 깨져 파서(Parser)를 터뜨린다면, 오라클 러너(Runner) 코드를 헐겁고 비굴하게 만들기보단 프롬프트를 뜯어고쳐야 한다. 에이전트의 시스템 메시지(System Prompt) 최상단에[CRITICAL WARNING: 너의 최종 응답은 반드시 순수한 RFC 8259 JSON 형식으로만 강제 출력하라. 코드 블록 백틱(```)이나 부연 설명 수다 따위의 평문은 절대 단 한 글자도 포함하지 말 것. 어길 시 시스템 페널티 부여.]와 같이 명시적이고 공포스러운 네거티브 제약(Negative Constraint)을 철퇴처럼 내리쳐 모델의 행동 반경 폭을 짐승처럼 좁혀버려야 한다.
소프트웨어 테스팅 학계의 뼈아픈 격언이 있다. “Flaky Test 곰팡이를 1개라도 어설프게 안고 가는 거대한 CI 시스템은, 아예 처음부터 테스트 방어막이 단 한 개도 없는 시스템보다 훨씬 더 파괴적이고 질이 나쁘다.”
결정론적 오라클 시스템을 구축하려는 창시자 아키텍트라면, 99번 기분 좋게 성공하고 단 1번 기분 나쁘게 실패하는 간헐적 테스트를 결코 ’그럴 수 있는 확률의 타협 대상’으로 안일하게 삼아서는 안 된다. 그것은 오라클이 최우선으로 격리하고 영원히 파괴해야 할 아키텍처의 적(Enemy) 그 자체임을 명심하라.