화이트박스 테스트에서 커버리지를 설계하는 방법
구조 기반 테스트의 문장·분기·조건·경로 커버리지 기준과 위험 기반 목표치, CI/CD 품질 게이트 운영 방식을 정리한다.
2026-08-14 · 최초 발행 2025-12-17
실행된 코드가 아니라, 실행되지 않은 흐름을 확인하는 테스트
구조 기반 테스트(Structure-based Testing)는 소스 코드 내부의 제어 흐름과 데이터 흐름을 기준으로 테스트 케이스를 설계하고 수행하며 측정하는 화이트박스 테스트 기법이다. 문장, 분기, 조건, 경로처럼 코드 안의 특정 요소 가운데 실제로 실행된 비율을 커버리지 지표로 삼아 테스트 충분성(Sufficiency)을 정량화한다.
목표는 일률적으로 정하지 않는다. 문장 ≥ 90%, 분기 ≥ 80%, 조건 ≥ 75%를 예로 둘 수 있으며, 고위험 모듈에는 경로 기반 기준을 선택적으로 적용한다. 사이클로매틱 복잡도는 제어 흐름 그래프의 독립 경로 수를 근사하는 지표다. 복잡도가 높아질수록 분기와 경로 커버리지를 달성하기는 기하급수적으로 어려워진다.
커버리지 기준이 보장하는 범위
문장(Statement) 커버리지는 실행 가능한 모든 문장이 최소 1회 실행됐는지를 본다. 코드의 사각지대를 줄이는 데는 효과적이지만, 논리 결함을 찾는 힘에는 한계가 있다.
분기(Branch/Decision) 커버리지는 모든 분기 결과(True/False)가 최소 1회 실행되도록 한다. 조건 조합 일부를 포괄하지만, 하나의 분기 안에 복합 조건이 있으면 조합이 빠질 수 있다.
조건(Condition) 커버리지는 복합 조건을 이루는 각 원자 조건이 True와 False를 최소 1회씩 갖게 한다. 조건 간 상호작용으로 생기는 결함을 더 잘 포착할 수 있지만, 각 조건이 의사결정 결과에 독립적으로 미친 영향까지 증명하지는 않는다.
경로(Path) 커버리지는 가능한 제어 흐름 경로의 실행을 보장한다. 논리 결함 탐지력은 가장 높지만 경로 폭발(Path Explosion) 문제가 있어, 고위험·고복잡 코드에 선별적으로 적용하는 편이 현실적이다.
MC/DC(Modified Condition/Decision Coverage)는 각 원자 조건이 단독으로 의사결정 결과에 영향을 준다는 점을 증명한다. 항공과 자동차 같은 안전 기준 영역에서 요구되는 수준이며, 표준 요구사항은 최신 정보 확인이 필요하다.
| 커버리지 | 강도 | 테스트 볼륨 영향 | 결함 발견력(논리) | 성능 영향(계측/실행) | 확장성(대규모 적용) | 일관성(측정 안정성) | 운영 편의 |
|---|---|---|---|---|---|---|---|
| 문장 | 하 | 낮음 | 낮음 | 낮음 | 높음 | 높음 | 높음 |
| 분기 | 중 | 중간 | 중간 | 낮음~중간 | 높음 | 높음 | 높음 |
| 조건 | 중~상 | 중간~높음 | 중~상 | 중간 | 중간~높음 | 높음 | 중간 |
| 경로 | 상 | 매우 높음 | 매우 높음 | 높음 | 낮음 | 중간 | 낮음 |
위험도와 복잡도에 맞춰 기준을 배치한다
커버리지 목표는 모듈의 위험도와 복잡도를 기준으로 차등화할 수 있다. 핵심 결제·인증 모듈에는 분기 90%+, 조건 80%+를 두고, 일반 유틸리티에는 문장 85% 수준을 적용하는 식이다.
사이클로매틱 복잡도도 전략을 가르는 기준이 된다. 복잡도 ≤ 10에서는 분기 중심으로 접근하고, 11~20에서는 조건 기준을 함께 적용한다. >20인 경우에는 리팩터링하거나 경로 기준을 선택 적용한다.
계측은 빌드 시 라인·분기 플래그를 삽입하고, 실행 중 히트맵을 수집한 뒤, 리포트를 생성하는 3단계 파이프라인으로 구성된다. 언어별 대표 도구로는 Python의 coverage.py, Java의 JaCoCo, JavaScript의 nyc/Istanbul, C/C++의 gcov/lcov, .NET의 Coverlet이 있다. 분기와 조건 지원 범위는 도구마다 다르므로 최신 정보 확인이 필요하다.
테스트 케이스는 결정 테이블, 경계값, 기본 경로(Path) 기법을 함께 사용해 설계한다. 복합 조건은 진리표를 축약하는 방식으로 MCDC 의사 적용을 하여 케이스 수를 줄일 수 있다. 외부 의존성은 Mock/Stub으로 격리하고, 데이터 페이로드를 최소화해 짧은 실행 시간을 확보한다.
PR 단위에서는 커버리지 변동(ΔCoverage)과 임계치 미달 여부를 품질 게이트에 연결할 수 있다. 신규 코드 기준(line diff) 측정도 함께 권장된다. 테스트 데이터는 트랜잭션으로 격리하고 롤백을 일괄 처리하며, 플래키 테스트의 자동 격리·재시도 정책을 정의해 일관성을 유지한다.
규제 대응과 리팩터링에서의 사용
안전 필수 도메인에서는 항공 DO-178C, 자동차 ISO 26262, 산업 IEC 61508 등의 표준을 준수하는 프로젝트에서 분기·조건·MC/DC 기반의 커버리지 목표를 설정한다. 구체적인 요구 수준은 버전과 모듈 등급에 따라 다르므로 최신 정보 확인이 필요하다. 변경 영향 분석과 결합하면 변경된 부분의 경로에 테스트를 집중할 수 있다.
레거시 모듈에서는 라인·분기 히트맵을 시각화해 죽은 코드와 미사용 분기를 식별한다. 이를 제거하거나 단순화하면 복잡도를 낮출 수 있다. 변경 전 커버리지 스냅샷을 베이스라인으로 보존하면 회귀 위험 관리에도 활용된다.
마이크로서비스와 데이터 계층에서는 서비스별로 독립적인 커버리지 게이트를 두고, 공통 라이브러리는 별도 목표치를 운영할 수 있다. DB 통합 테스트는 트랜잭션 경계 안에서 실행한 뒤 롤백하고, 락 경합을 모의해 동시성 경로를 검증한다.
측정 지표가 만드는 품질 변화
구조 기반 테스트를 운영하면 회귀 결함률은 2040% 감소하고, 장애 재현 시간은 1530% 단축되며, 변경 리드타임은 1020% 감소할 수 있다. 이는 도구와 조직 성숙도에 따라 편차가 있다. 코드 복잡도가 15% 감소하면 경로 보장 비용은 2035% 절감되는 것으로 추정된다.
수치 외에도 테스트 충분성이 가시화되면서 리뷰 품질과 배포 신뢰도를 높일 수 있다. 위험 기반 품질 기준은 리소스를 집중할 지점을 드러내고, 변경 판단의 일관성을 확보하는 기준이 된다.
Python에서 분기 커버리지를 확인하는 예시
전제조건: Python 3.10+, coverage 7.6+, pytest 7+
설치
pip install coverage==7.6.0 pytest==7.4.0
예시 코드: payment.py
# payment.py
def calc_discount(amount: float, tier: str, is_new: bool) -> float:
if amount <= 0:
raise ValueError("amount must be positive")
rate = 0.0
if tier == "VIP":
rate = 0.20
elif tier == "GOLD":
rate = 0.10
else:
rate = 0.0
if is_new and amount > 100:
rate += 0.05 # 복합 조건: is_new AND amount>100
final = amount * (1 - rate)
return round(final, 2)
테스트: test_payment.py
# test_payment.py
import pytest
from payment import calc_discount
def test_vip_new_over_100():
assert calc_discount(200, "VIP", True) == 200 * (1 - 0.25)
def test_gold_existing():
assert calc_discount(200, "GOLD", False) == 200 * (1 - 0.10)
def test_basic_small_amount():
assert calc_discount(50, "BASIC", True) == 50 # 100 이하, 추가 할인 미적용
def test_invalid_amount():
with pytest.raises(ValueError):
calc_discount(0, "VIP", True)
실행
- 문장 커버리지:
coverage run -m pytest -q && coverage report -m - 분기 커버리지:
coverage run --branch -m pytest -q && coverage report -m - .coveragerc로 상시 분기 수집
[run]
branch = True
분기와 조건 기준에서는 복합 조건의 각 원자 조건이 True/False를 모두 충족하는지 리포트로 확인한다. 필요하면 테스트 케이스를 추가로 분화한다. 외부 의존 호출은 Mock로 격리하고, 테스트 데이터는 픽스처로 재사용하며, 테스트 간 트랜잭션 롤백으로 일관성을 유지한다.
커버리지를 품질 게이트로 다룰 때
구조 기반 테스트는 소스 제어 흐름을 기준으로 테스트 충분성을 정량 관리하는 체계다. 문장, 분기, 조건, 경로 기준은 강도를 점진적으로 높이는 선택지이며, 위험도와 복잡도에 따라 적용 범위를 달리해야 한다. 계측 자동화와 CI/CD 게이트를 연결하면 리팩터링과 규제 대응 과정에서도 품질 기준을 일관되게 유지할 수 있다.