소스코드 커버리지로 테스트 공백 관리하기

소스코드 커버리지의 유형과 측정 기준, 목표 설정 방식, 자동화 도구 활용 및 품질 지표로서의 한계를 정리합니다.

2026-08-14 · 최초 발행 2025-05-23

테스트가 지나가지 않은 코드를 드러내는 지표

소스코드 커버리지(Code Coverage)는 테스트 실행 중 프로그램 소스코드가 어느 정도 실행됐는지를 측정하는 지표다. 어떤 코드가 실제로 실행됐는지와 테스트된 코드의 비율을 수치로 표현한다.

이 지표는 테스트 케이스의 효율성과 완전성을 평가하는 객관적인 기준이 된다. 아직 테스트되지 않은 영역을 찾아내면 잠재적인 버그나 취약점이 남아 있을 가능성이 있는 부분을 점검할 수 있다.

커버리지 분석은 내부 구조를 기준으로 테스트 효과를 평가하는 화이트박스 테스팅의 한 형태다. 일반적으로 자동화 도구가 코드 실행을 추적해 결과를 수집한다.

실행 단위에 따라 달라지는 측정 방식

구문이 실제로 실행됐는지 확인하기

구문 커버리지(Statement Coverage)는 실행 가능한 각 구문이 얼마나 수행됐는지를 보는 가장 기본적인 방식이다.

실행된 구문 수 / 전체 구문 수 × 100%

다음 코드에서는 조건문 안의 대입문까지 실행됐는지가 측정 대상이다.

public int calculateDiscount(int purchaseAmount) {
    int discount = 0;
    if (purchaseAmount > 1000) {
        discount = 100;
    }
    return discount;
}

calculateDiscount(1500)을 실행하면 모든 구문이 실행돼 100% 구문 커버리지가 된다. 반면 calculateDiscount(500)만 실행하면 if 조건 내부 구문은 실행되지 않아 구문 커버리지가 약 67%가 된다.

분기 결과를 모두 통과시키기

분기 커버리지(Branch Coverage)는 if, switch 같은 조건부 분기에서 각 결과가 실행됐는지를 측정한다.

실행된 분기 수 / 전체 분기 수 × 100%

앞선 코드라면 purchaseAmount > 1000이 true인 경우와 false인 경우를 모두 테스트해야 100% 분기 커버리지가 된다.

복합 조건의 결과를 확인하기

조건 커버리지(Condition Coverage)는 각 조건식이 낼 수 있는 결과를 테스트했는지 측정한다.

실행된 조건 결과 수 / 가능한 모든 조건 결과 수 × 100%

복합 조건에서는 조건별 조합을 고려해야 한다.

if (age > 18 && income > 30000) {
    // 실행 코드
}

이 조건에는 다음 네 가지 조합이 있다.

  • age > 18 true, income > 30000 true
  • age > 18 true, income > 30000 false
  • age > 18 false, income > 30000 true
  • age > 18 false, income > 30000 false

가능한 실행 경로를 추적하기

경로 커버리지(Path Coverage)는 프로그램에서 가능한 모든 실행 경로가 테스트됐는지를 측정한다.

실행된 경로 수 / 가능한 모든 경로 수 × 100%

가장 철저한 방식이지만 가능한 경로 수가 기하급수적으로 증가할 수 있어, 실제로 100%를 달성하기 어려운 경우가 많다.

호출 여부를 보는 함수 커버리지

함수 커버리지(Function Coverage)는 프로그램의 모든 함수가 적어도 한 번 호출됐는지를 확인한다.

호출된 함수 수 / 전체 함수 수 × 100%

도구가 실행 데이터를 보고서로 바꾸는 과정

커버리지 분석은 자동화 도구로 수행할 수 있다. Java에서는 JaCoCo(Java Code Coverage)를 사용할 수 있으며 Maven 및 Gradle과 통합하고 HTML, XML, CSV 형식의 보고서를 지원한다. JavaScript에서는 Node.js 프로젝트와 브라우저 및 서버 측 JavaScript를 지원하는 Istanbul이 사용된다.

Java 프로젝트에서는 Cobertura도 사용할 수 있고, CI/CD 파이프라인과 통합하기 쉽다. C/C++ 프로그램에는 gcc 컴파일러와 함께 제공되는 gcov/lcov가 있으며, Python에서는 라인·브랜치·경로 커버리지를 지원하는 Coverage.py를 활용할 수 있다.

소스코드계측된 코드테스트 실행실행 데이터 수집커버리지 보고서 생성시각화 분석

위험도와 제약을 반영해 목표를 정한다

커버리지 목표는 모든 프로젝트에 동일하게 적용할 수 없다. 안전 중요 시스템은 90-100% 구문 및 분기 커버리지를, 상업용 애플리케이션은 70-80% 구문 커버리지를, 프로토타입 또는 실험적 코드는 50-60% 구문 커버리지를 목표로 설정할 수 있다.

목표를 정할 때는 비즈니스 중요도, 위험 수준, 규제 요구사항, 리소스 제약을 함께 봐야 한다. 지표를 높이는 것 자체가 목적이 되면 테스트의 가치가 낮아질 수 있다.

테스트 주도 개발(TDD)은 코드 작성 전에 테스트 케이스를 설계해 자연스럽게 높은 커버리지를 확보하는 방식이다. 코드 리뷰에서는 변경 후 커버리지가 감소했는지 확인하고, CI/CD 파이프라인에는 빌드 과정의 자동 검사와 보고 단계를 포함할 수 있다.

미테스트 영역은 복잡성, 사용 빈도, 비즈니스 중요도를 기준으로 우선순위를 정한다. 커버리지 보고서는 개발 팀 전체가 주기적으로 검토해야 한다.

높은 수치만으로 품질을 말할 수 없는 이유

100% 커버리지가 모든 버그를 발견한다는 보장은 없다. 코드가 실행됐다는 사실과 올바르게 테스트됐다는 사실은 다르며, 결국 테스트 케이스의 품질이 더 중요하다.

데이터베이스나 API 같은 외부 시스템과의 상호작용은 커버리지만으로 완전히 측정하기 어렵다. 커버리지 수치만 높이기 위한 테스트는 실제 가치가 낮을 수 있고, 지나치게 엄격한 요구사항은 개발 속도를 저하시킬 수도 있다.

코드 커버리지정적 코드 분석동적 테스팅수동 테스트품질 보증성능 테스트

기능 테스트, 통합 테스트, 인수 테스트 등 여러 레벨의 테스트를 조합해야 한다. SonarQube, ESLint 같은 정적 코드 분석 도구도 코드 품질 검사에 활용할 수 있다. 사용자 시나리오 기반의 탐색적 테스팅은 자동화 테스트가 놓친 부분을 보완하며, 뮤테이션 테스팅은 의도적으로 결함을 주입한 뒤 테스트가 이를 탐지하는지 확인한다.

커버리지를 운영에 연결한 사례

주요 은행의 핵심 거래 시스템 개발 프로젝트에서는 코드 커버리지를 90% 이상 유지하는 정책을 도입했다. 그 결과 프로덕션 환경 배포 후 크리티컬 버그가 70% 감소했고, 운영 중 긴급 패치 횟수는 50% 감소했으며 개발자의 코드 품질 의식도 향상됐다.

글로벌 전자상거래 기업은 CI/CD 파이프라인에 커버리지 분석 단계를 넣었다. 모든 PR(Pull Request)에 자동 검사를 실행하고, 임계값에 미달하면 빌드를 실패 처리하며, 커버리지 리포트를 개발자에게 자동 전송하는 방식이다. 이 환경에서는 테스트 코드 작성 문화가 확립됐고, 미테스트 코드로 인한 회귀 버그 발생 비율이 65% 감소했으며 릴리스 주기가 30% 단축됐다.

15년 된 대규모 레거시 시스템의 현대화 프로젝트에서는 초기 커버리지가 약 15%인 상태에서 시작했다. 비즈니스 가치와 위험이 높은 모듈부터 테스트를 작성하고, 신규 코드에 최소 70% 커버리지 요구사항을 적용했으며 분기별 목표를 설정해 점검했다. 18개월 후 전체 시스템 커버리지는 60%까지 향상됐고, 프로덕션 장애 발생률은 85% 감소했다.

소스코드 커버리지화이트박스 테스팅테스트 품질CI/CD품질 보증