🧬 MutantHunter

테스트가 못 잡는 구멍을 찾아 테스트를 만들고,
실제로 버그를 잡는지 실행으로 증명한 것만 PR에 제안합니다.

왜 만들었나

커버리지는 “그 줄이 실행됐는가”만 봅니다. “그 줄이 틀렸을 때 누가 알아채는가”는 묻지 않습니다.

export function grade(score: number) {
  if (score >= 90) return "A";   // 테스트가 이 줄을 실행은 함
  return "F";
}

grade(95)만 테스트하면 커버리지는 올라가지만, 누가 >= 90>= 10으로 바꿔도 아무 테스트도 실패하지 않습니다. 그런 지점을 찾아 메우는 도구입니다.

동작

PR diff → 변경된 코드를 일부러 망가뜨림 (뮤테이션)
        → 테스트 재실행
        → 전부 통과? = 그 코드는 틀려도 아무도 모른다
        → LLM이 그 구멍을 막는 테스트 생성
        → 5개 게이트로 검증
        → 통과한 것만 PR 코멘트
핵심은 세 번째 게이트입니다. 현재 코드에서 통과하는 그럴듯한 테스트는 얼마든지 만들어집니다. 실측에서 뮤턴트 102개를 돌렸을 때 생성 테스트 157건을 폐기했고, 그중 53건이 “통과하지만 결함은 못 잡는” 테스트였습니다. 코드 리뷰로는 걸러내기 어렵습니다.

언제 값을 내는가

대상뮤테이션 스코어채택
unjs/ufo88%0 / 3
unjs/destr86%0 / 7
antfu/utils0%6 / 7

이미 잘 테스트된 코드에는 제안할 것이 없고, 그때 침묵하는 것이 올바른 동작입니다. 테스트가 얇은 코드에서 값을 냅니다.

쓰는 법

대상 저장소에 커밋되는 것은 워크플로우 파일 하나뿐입니다.

- uses: actions/checkout@v4
  with: { fetch-depth: 0 }
- uses: actions/setup-node@v4
  with: { node-version: 20 }
- run: npm ci
- uses: PYSoYa/mutant-hunter@v1
  with:
    github-token: ${{ secrets.GITHUB_TOKEN }}
  env:
    MH_PROVIDER: mistral
    MH_API_KEY: ${{ secrets.MISTRAL_API_KEY }}

TypeScript / JavaScript · vitest 또는 jest · 무료 API 키 하나 (Gemini · Groq · Mistral · OpenRouter)

만들면서 배운 것

측정 과정과 그때마다 틀린 것은 측정 기록에 남겼습니다.