
더 나은 AI 생성 테스트를 찾다가 결국 Mutagen을 만들게 된 이야기
요약
LLM이 생성한 테스트의 품질을 검증하기 위해 변이 테스트(Mutation Testing) 기법을 도입한 Mutagen 프로젝트를 소개합니다. 단순히 코드 커버리지를 높이는 것을 넘어, 의도적인 코드 결함을 테스트가 감지할 수 있는지 확인하여 테스트의 실효성을 보장합니다.
핵심 포인트
- LLM 생성 테스트의 낮은 신뢰성 문제를 변이 테스트로 해결
- 코드 변이 시 결함을 감지하지 못하는 테스트는 자동으로 폐기
- 오케스트레이션, 병렬 처리, 상태 관리 등 시스템 설계의 중요성 강조
- AST 기반 타겟 선택 및 SQLite 체크포인팅 등 기술적 구현
지난 몇 달 동안 LLM (Large Language Models)을 사용하여 테스트를 생성하는 도구들을 점점 더 많이 보게 되었습니다.
데모들은 인상적입니다.
모델을 코드베이스에 지정하고 몇 초만 기다리면, 갑자기 수십 개의 새로운 테스트가 생겨납니다.
하지만 그런 데모를 볼 때마다 저는 항상 똑같은 의문이 들었습니다.
생성된 테스트가 실제로 좋은지 어떻게 알 수 있을까요?
커버리지 (Coverage)가 도움이 되긴 하지만, 어느 정도까지만 그렇습니다.
A 테스트는 코드의 동작을 실제로 검증하지 않고도 코드 라인을 실행할 수 있습니다.
그리고 AI가 생성한 테스트는 당신이 실제로 신경 써야 할 버그를 완전히 놓치면서도 겉보기에는 완벽하게 합리적으로 보일 수 있습니다.
그 질문이 주말 프로젝트로 이어졌습니다.
저는 Mutagen을 만들었습니다.
Mutagen이란 무엇인가요?
높은 수준에서 설명하자면, Mutagen은 LLM을 사용하여 테스트를 생성한 다음 즉시 그 테스트들을 망가뜨리려고 시도합니다.
워크플로우는 대략 다음과 같습니다:
- 저장소(Repository)를 클론하거나 가져오기
- 코드베이스를 분석하고 테스트 대상 식별하기
- LLM으로 pytest 테스트 생성하기
- 격리된 환경에서 테스트 실행하기
- 소스 코드를 변이(Mutate)시키고 변이 테스트 (Mutation Testing) 실행하기
- 도입된 결함을 감지할 수 있는 테스트만 남기기
변이 테스트 단계가 흥미로운 부분입니다.
다음과 같이 묻는 대신:
테스트가 실행되었는가?
또는
커버리지가 증가했는가?
Mutagen은 다음과 같이 묻습니다:
내가 의도적으로 코드를 망가뜨린다면, 이 테스트가 이를 알아차리는가?
만약 대답이 **아니오 (no)**라면, 생성된 테스트는 폐기됩니다.
예상치 못한 부분
이를 만들면서 예상하지 못했던 한 가지는, 도전 과제의 상당 부분이 LLM과는 아무런 관련이 없었다는 점입니다.
많은 작업이 결국 오케스트레이션 (Orchestration)과 신뢰성 (Reliability)에 관한 것이었습니다.
실행은 재개 가능해야 했습니다.
대상은 병렬로 처리되어야 했습니다.
실패는 복구 가능해야 했습니다.
상태 전이 (State transitions)는 제어 흐름 (Control flow) 내부에 숨겨지기보다 명시적이어야 했습니다.
다음과 같이 시작했던 것이:
"테스트를 생성하고 mutmut을 실행하라"\n
라는 문구로 시작했던 것이 결국 다음과 같이 성장했습니다:
- 클린 / 육각형 아키텍처 (Clean / Hexagonal Architecture)
- 플러그인이 가능한 다중 LLM 제공업체 (Multiple pluggable LLM providers)
- AST 기반 타겟 선택 (AST-based target selection)
- 변이 기반 테스트 생성 (Mutation-gated test generation)
- SQLite 기반 체크포인팅 (SQLite-backed checkpointing)
- 병렬 실행 (Parallel execution)
- 선택적 콜 그래프 분석 (Optional call-graph analysis)
- 기존 테스트 스위트에 대한 선택적 검색 (Optional retrieval over existing test suites)
- CI 친화적인 종료 코드 (CI-friendly exit codes)
- 11,000라인이 조금 넘는 소스 코드
내가 가장 자랑스럽게 생각하는 부분
내가 가장 만족하는 기능은 아마도 피드백 루프 (Feedback loop)일 것입니다.
변이 (Mutations)가 생존하면, Mutagen은 그 생존한 변이들을 모델에 다시 전달하여, 모델이 놓친 바로 그 사각지대에 대해 테스트를 강화하도록 요청합니다.
따라서 무작정 테스트를 생성하는 대신, 증거를 바탕으로 반복 (Iterate)합니다.
다음과 같이 말하는 것이 아니라:
"다른 테스트를 작성해줘."
다음과 같이 말합니다:
"당신은 이러한 특정 결함들을 놓쳤습니다. 다시 시도하세요."
이 작은 변화가 결국 엄청난 차이를 만들어냈습니다.
내가 배운 것
이 프로젝트는 이제 오픈 소스이며, PyPI에서 설치할 수 있고, 문서화가 완벽하게 되어 있습니다.
다음과 같이 시작했던 것이:
"더 나은 테스트를 생성할 수 있는지 한번 보자."
어떻게 된 일인지 수천 줄의 코드, 변이 테스트 파이프라인 (Mutation testing pipelines), 상태 머신 (State machines), 체크포인팅 시스템 (Checkpointing systems), 검색 메커니즘 (Retrieval mechanisms), 그리고 주말 동안 계획했던 것보다 훨씬 적은 수면 시간으로 변해버렸습니다.
그리고 솔직히 말해서, 그렇게 되어서 기쁩니다.
왜냐하면 내가 배운 가장 흥미로운 점은 LLM에 관한 것이 아니었기 때문입니다.
그것은 바로 이것이었습니다:
무언가를 생성하는 것은 쉽다.
그것이 실제로 유용한지 증명하는 것이 진짜 엔지니어링이 시작되는 지점이다.
Mutagen은 적어도 테스트에 있어서만큼은, 그 문제를 해결하려는 나의 시도입니다.
확인해 보세요
GitHub
krish-arya / mutagen
Mutagen
변이 테스트 (Mutation testing)로 검증되는 LLM 지원 테스트 생성.
Mutagen은 Python 저장소(repository)를 입력받아, 테스트 커버리지가 낮은 함수를 찾아내고, LLM을 사용하여 해당 함수들에 대한 pytest 테스트를 생성하며, 대상의 **변이(mutants)를 실제로 제거(kill)**하는 테스트만을 남깁니다. 이 프로젝트는 엄격한 의존성 규칙을 가진 클린 아키텍처 (Clean Architecture), 두 개의 명시적인 상태 머신 (state machines), 완전한 비동기 I/O (async I/O), SQLite 기반의 재개 (resume) 기능, 그리고 구조화된 로깅 (structured logging)을 기반으로 구축되었습니다.
repo ──► ingest ──► select targets ──► generate tests ──► run ──► mutate ──► keep / discard ──► report
▲ │
└── repair / strengthen loops ──┘
기능
선택된 각 대상에 대해 파이프라인은 다음과 같이 동작합니다:
- 생성 (Generates): 함수의 소스 코드, 임포트 (imports), 그리고 주변 컨텍스트 (context)를 바탕으로 프로젝트의 기존 테스트 스타일과 일치하는 pytest 모듈을 생성합니다.
- 실행 (Runs): 격리된 서브프로세스 샌드박스 (subprocess sandbox) 내에서 실행합니다 (타임아웃 및 리소스 제한, 그리고 이중 실행을 통한 불안정성 (flakiness) 탐지 포함).
- 변이 게이트 (Mutation-gates): mutmut을 사용하여 변이 테스트를 수행합니다. 만약 테스트가 충분한 변이들을 제거하지 못하면, 살아남은 변이들은 재생성을 위한 **피드백 (feedback)**이 됩니다…
문서 (Documentation)
설치 (Installation)
pip install mutagen-ai
엔지니어, 테스터, 그리고 빌더분들의 진심 어린 피드백을 기다리고 있습니다.
이전에 AI가 생성한 테스트를 사용해 보신 적이 있다면, 여러분도 저와 같은 신뢰 문제 (trust problem)를 겪으셨는지 특히 궁금합니다.
ps: 제안 사항이 있다면 krisharya2k5@gmail.com으로 개인적으로 메일 주셔도 좋습니다 !!!
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기