테스트 커버리지의 함정: Stryker와 Cosmic Ray를 활용한 변이 테스트 소개

발행: (2026년 3월 17일 PM 07:20 GMT+9)
7 분 소요
원문: Dev.to

Source: Dev.to

Overview

Goal: 코드 커버리지 메트릭의 한계를 극복하고 뮤테이션 테스트를 도입하여 테스트 스위트가 실제로 비즈니스 로직의 오류를 잡아내는지 검증합니다.

Scope: 엔터프라이즈 오케스트레이터 프로젝트 (Ochestrator)의 핵심 모듈을 프론트엔드(TypeScript)와 백엔드(Python) 모두에 적용합니다.

Expected Results: 단순 라인 커버리지를 넘어서는 뮤테이션 스코어를 확보함으로써 코드 안정성과 테스트 신뢰성을 향상시킵니다.

우리는 종종 높은 테스트 커버리지가 안전한 코드를 의미한다고 믿습니다. 하지만 다음 질문에 답하기는 어렵습니다:

“테스트를 누가 검증하나요?”

단순히 코드를 실행하고 적절한 어설션이 없는 테스트도 커버리지 메트릭에 기여합니다. 이 커버리지 함정을 해결하기 위해 우리는 뮤테이션 테스트를 도입했습니다.

Mutation Testing Flow

구현

1. TypeScript 환경 – Stryker Mutator

프론트엔드와 공통 유틸리티를 위한 TypeScript 환경에서는 Stryker 를 선택했습니다. Vitest와 잘 통합되며 설정이 간단합니다.

기술 스택: TypeScript, Vitest, Stryker Mutator

핵심 설정 (stryker.config.json):

{
  "testRunner": "vitest",
  "reporters": ["html", "clear-text", "progress"],
  "concurrency": 4,
  "incremental": true,
  "mutate": [
    "src/utils/**/*.ts",
    "src/services/**/*.ts"
  ]
}

incremental 옵션을 활성화하여 변경된 파일에 대해서만 변이 테스트가 실행되도록 했습니다.

2. Python 환경 – Cosmic Ray

백엔드에서는 Cosmic Ray 를 도입했습니다. Python의 동적 특성을 활용해 AST(추상 구문 트리)를 조작함으로써 강력한 변이를 생성합니다.

기술 스택: Python, Pytest, Cosmic Ray, Docker

실행 아키텍처: 변이 테스트는 리소스를 많이 사용하므로 여러 Docker 워커에 걸쳐 병렬로 실행합니다.

# Partial docker-compose.test.yaml
cosmic-worker-1:
  command: uv run cosmic-ray worker cosmic.sqlite

cosmic-runner:
  depends_on: [cosmic-worker-1, cosmic-worker-2]
  command: |
    uv run cosmic-ray init cosmic-ray.toml cosmic.sqlite
    uv run cosmic-ray exec cosmic-ray.toml cosmic.sqlite

디버깅 / 도전 과제

실제 사례: VideoSplitter.ts에서 살아남은 뮤턴트

videoSplitter.ts는 95 % 이상의 라인 커버리지를 가지고 있었지만, Stryker는 메모리‑체크 로직에서 많은 살아남은 뮤턴트를 발견했습니다.

원본 코드

// videoSplitter.ts
if (availableMemory  {
  // Simulate situations where memory is exactly equal to or slightly less than requiredMemory
  // ... reinforced test code ...
});

이러한 테스트를 추가한 후, 이전에 살아남았던 뮤턴트들이 사멸되었습니다.

결과

성과

  • 핵심 유틸리티 모듈에서 12개의 살아남은 변이체를 발견하고 제거했습니다.
  • 테스트 코드를 단순히 “실행”하는 수준에서 실제로 “검증”하는 수준으로 끌어올렸습니다.

핵심 지표

지표이전이후
변이 점수62 %88 %
회귀 버그여러 개 (잠재적)CI에서 관찰된 것이 없음

신뢰성: test:mutation 스크립트가 이제 매 배포 전 자동으로 실행되어 회귀를 방지합니다.

사용자 피드백

“이제 테스트를 신뢰하고 자신 있게 리팩터링할 수 있습니다.” – 팀원

Key Takeaways

  • Coverage는 시작에 불과합니다 – 라인 커버리지는 테스트되지 않은 것을 알려주며, 테스트된 것의 품질을 알려주지는 않습니다.
  • Mutation 테스트는 비용이 많이 들지만 그만한 가치가 있습니다 – 전체 실행은 수십 분이 걸릴 수 있지만, 핵심 비즈니스 로직에 대한 효과는 막대합니다.
  • 점진적 도입이 효과적입니다 – 성공 사례를 만들기 위해 고영향 모듈(예: VideoSplitter)부터 시작하고 점차 확대합니다.

Verification Checklist

  • 개요 – 목표와 범위가 명확합니다.
  • 구현 – 기술 스택과 코드 예제가 포함되어 있습니다.
  • 디버깅 – 최소 하나의 구체적인 문제와 그 해결책이 설명되어 있습니다.
  • 결과 – 수치 데이터와 성과 지표가 포함되어 있습니다.
  • 핵심 요점 – 배운 교훈과 향후 계획이 정리되어 있습니다.

길이 가이드라인

  • 전체: 400–800줄 (현재 약 100줄 – 필요 시 확장 가능).
  • 각 섹션: 최소 50줄.

문서는 구조와 내용 요구 사항을 충족하면서도 깔끔하고 읽기 쉽습니다.

Lines (if possible)

- [x] Code examples: 2–3 examples included
0 조회
Back to Blog

관련 글

더 보기 »

다음 순열

문제 설명: 주어진 숫자 배열의 next permutation을 계산하는 것이 과제이다. permutation은 동일한 원소들의 재배열이며, 다음…