에이전트가 만든 테스트는 믿을 수 없다
원문은 Alex O'Callaghan님이 에 게재했습니다. 이 블로그 구독하기
에이전트를 이용해 53개의 Enzyme 테스트 스위트를 React Testing Library로 마이그레이션했다. 테스트는 모두 통과했고 코드도 일관성 있어 보였지만, 자세히 들여다보니 회귀를 잡아내지 못하는 테스트, 잘못된 대상을 검증하는 테스트, 사실상 아무것도 테스트하지 않는 테스트들이 있었다.
에이전트가 생성한 테스트에서는 이런 문제를 놓치기 쉽다. 결과물은 깔끔해 보이고 코드는 정리되어 있으며 양도 방대하기 때문이다.
Enzyme에서 RTL로의 마이그레이션
Enzyme 테스트는 몇 년 동안 낮은 우선순위로 백로그에 쌓여 있던 기술 부채였다. 잘 정의되어 있고 기계적인 작업이라 에이전트가 잘할 것 같은 종류의 일이었다. 복잡도별로 작업을 나누고, 내가 만든 prepare-mr-skill로 커밋을 구조화하고 설명을 작성했더니 일이 되는 것처럼 보였다. 적어도 겉보기에는 그랬다. 테스트는 마이그레이션됐고, 통과했으며, 코드 변경도 합리적으로 보였다.
병합하기 전에 평소대로 팀 리뷰 절차에 따라 MR을 검토했는데, 겉보기에는 정확해 보이지만 회귀를 잡아내지 못하는 테스트들이 눈에 띄었다. 예를 들어 특정 ARIA role을 가진 요소가 렌더링되지 않았음을 검증하는 테스트가 있었는데, 그 role 자체가 유효하지 않아 애초에 컴포넌트가 해당 요소를 렌더링할 수 없는 경우였다. 또 disabled와 aria-disabled를 혼동한 경우도 있었다. 두 속성은 동작이 다르고 접근성 측면에서 중요한 차이를 가지지만, 보기에는 비슷해서 그럴듯해 보이는 테스트가 실패하지 않으면서도 잘못 작성될 수 있다.
왜 이런 일이 생기는가
이 문제는 에이전트만의 것이 아니다. 사람이 직접 작성해도 이런 테스트를 쉽게 만들 수 있다. 다만 잘못된 검증을 작성하는 사람이라면 보통 컴포넌트를 잘 알고 있어서 테스트가 너무 쉽게 통과한다는 느낌을 알아챌 수 있다. 에이전트에게는 그런 직관이 없다. 구현을 보고 패턴을 맞춰 그럴듯해 보이는 결과를 만들어낸 뒤 다음으로 넘어갈 뿐이다. 게다가 에이전트가 만들어내는 코드 양이 워낙 많다 보니 이런 문제가 더 쉽게 빠져나간다.
이미 구현이 존재하는 경우(예: 테스트 마이그레이션, 커버리지 보강, 몇 년 전에 작성된 테스트 검증)에는 Test Driven Development(TDD)의 자연스러운 안전장치가 동작하지 않는다. 이미 동작하는 코드를 대상으로 테스트를 작성하므로, 잘못된 검증이 실패할 기회 자체가 없다. 이를 잡아내는 유일한 방법은 일부러 컴포넌트를 망가뜨려 보는 것이다. 컴포넌트에 임시로 변경을 가하고 테스트가 이를 잡아내는지 확인한 뒤 되돌리는 방식이다.
검증이 실제로 동작하게 만들기
가장 먼저 떠오른 방법은 프롬프트를 수정해 에이전트가 이런 실수를 반드시 확인하도록 강제하는 것이었다. RTL 마이그레이션 스킬을 업데이트해 모든 테스트를 실패 상태에 대해 검증하도록 명시적으로 요구했다.
하지만 안정적으로 동작하지 않았다. 에이전트는 요구사항을 고려는 하되 가끔 뭔가를 잡아내고는 그냥 넘어갔다. 검증을 제약 조건이 아니라 체크박스 정도로 취급한 것이다.
문제는 일부 구조적인 측면도 있다. 에이전트에게 많은 테스트를 한 번에 마이그레이션하라고 하면 작업이 길어지고 컨텍스트가 가득 찬다. 컨텍스트가 길어질수록 모델은 지시사항에 대한 포커스를 잃기 시작한다. 일부 모델에서는 컨텍스트 윈도의 끝에 가까워질수록 일을 일찍 마무리하려는 “컨텍스트 불안” 현상을 보이기도 한다. 이 때문에 에이전트는 이런 검증 지시사항을 잊거나 건너뛰기 시작한다.
한 번에 처리하는 대신 테스트 스위트별로 마이그레이션을 실행해 봤다. 컨텍스트 윈도를 짧게 하면 완료해야 한다는 압박이 줄어들고, 에이전트가 검증 단계에서 더 천천히 작업할 여유가 생길 거라 생각했다. 실제로 에이전트는 검증할 가능성이 높아졌지만, 매 테스트를 검증하기보다는 “몇 가지 핵심 테스트”만 검증하기로 결정하는 경우가 많았다.
마지막으로 마이그레이션과 리뷰 단계를 두 개의 별도 에이전트 작업으로 나누기로 했다. 각 테스트 스위트를 순회하면서 두 개의 에이전트 프롬프트를 순차적으로 실행하는 bash 스크립트를 작성했다. 하나는 마이그레이션을, 다른 하나는 리뷰를 담당한다.
#!/bin/bash
echo "Starting migration..."
declare -a files=(
"path/to/test-suite.test.tsx"
)
for i in "${files[@]}"; do
echo "Migrating $i"
agent -p --force --output-format stream-json --stream-partial-output --model claude-4.6-sonnet-medium \
"Migrate $i to use RTL. Ensure linting passes and then commit your changes in a single commit."
agent -p --force --output-format stream-json --stream-partial-output --model claude-4.6-sonnet-medium \
"Review the RTL tests in $i -
* Identify any unnecessary tests, remove them
* Identify any tests not following best practices, fix them
* For every single test intentionally change the implementation to break the specific feature tested and confirm the test fails as expected, fix them if they don't
Ensure linting passes and then commit your changes in a single commit."
echo "Migrated $i"
done검증에만 집중하는 작업이 되자 에이전트는 스스로 할 일 목록을 만들고 각 테스트를 빠짐없이 검토하며 문제를 잡아냈고, 리뷰에서 발견된 것 이상의 개선도 만들어냈다.
비용은 얼마나 들었나
이 방식은 동작했지만 비용이 훨씬 더 들었다. 모든 마이그레이션은 Cursor에서 claude-4.6-sonnet-medium을 사용해 22개의 테스트 스위트를 대상으로 실행했다.
| 방식 | 비용 |
|---|---|
| 단일 배치 처리 | ~$13 |
| 스위트별 처리 | ~$32 |
| 스위트별 처리 + 리뷰어 | ~$62 |
스위트별 리뷰어 단계를 거치자 사람이 리뷰에서 잡아냈던 모든 문제가 해결됐지만, 단일 배치 처리에 비해 비용이 거의 5배 증가했다.
에이전트 덕분에 더 많은 일을 할 수 있게 됐다. 백로그에만 쌓여 있었을 현대화 작업을 완료할 수 있게 된 것이다. 하지만 신뢰할 수 있는 결과로 제대로 하려면 생각보다 비용이 더 든다. 할 거라면 제대로 해야 한다고 생각하지만, 소요 시간은 크게 줄더라도 이 작업에 드는 실제 금전적 비용 사이의 트레이드오프가 존재한다.
조직은 이렇게 높아진 생산성이 단순히 AI 벤더 청구서상의 비용 증가로 끝나지 않고 어떻게 수익 증가로 이어질 수 있을지 의도적으로 고민해야 한다.
교훈
두 개의 프롬프트로 나눈 스크립트는 더 나은 프롬프트가 아니라 다른 아키텍처였다. 하나의 에이전트에게 같은 실행 안에서 마이그레이션과 검증을 함께 시키면 작업 구조 자체가 검증을 방해한다. 특정 과정 단계가 계속 누락된다면, 해결책은 보통 더 나은 지시가 아니다. 그 단계를 건너뛸 수 없는 워크플로를 만드는 것이다.
개념적으로 보면 여기서 리뷰어가 하는 일은 뮤테이션 테스팅이다. 각 검증마다 컴포넌트에 변화를 주면 테스트가 실패하는지 묻는 것이다. Stryker 같은 뮤테이션 테스팅 도구를 테스트 파이프라인에 도입하면 이런 문제를 잡아내는 데 도움이 되고, 에이전트가 수동으로 하던 작업을 대체해 비용을 줄일 수도 있다.
에이전트 워크플로를 설계하는 데 드는 시간도 작업의 일부이며, 에이전트 사용으로 인한 생산성 향상을 평가할 때 고려해야 한다. 그것이 신뢰할 수 있는 결과물과 그저 신뢰할 수 있어 보이는 결과물을 가르는 차이이다.
글을 무작위로 읽기
댓글
로그인하고 댓글 남기기