화이트박스 테스트로 제어 흐름과 커버리지를 검증하는 방법

화이트박스 테스트의 커버리지 기준, 경로 기반 설계, 테스트 더블, CI/CD 품질 게이트 운영 방식을 정리합니다.

2026-08-14 · 최초 발행 2025-12-21

코드 내부 경로를 기준으로 테스트를 설계한다

화이트박스 테스트는 소스 코드가 실제로 어떤 흐름으로 실행되는지를 보고 검증하는 방법이다. 제어 흐름, 분기 조건, 예외 처리, 상태 전이를 따라 테스트 케이스를 만들며, 단위 테스트에서 가장 먼저 적용할 수 있다. 모듈이나 서비스가 맞닿는 구간의 경계 조건과 오류 처리 로직으로도 범위를 넓힐 수 있다.

검증 결과는 Statement, Branch, Condition-Decision, Path, MC/DC 같은 커버리지 지표로 관리한다. 이를 위해서는 소스 코드에 접근할 수 있어야 하고, 계측(Instrumentation)이 가능한 환경과 Stub·Mock 같은 테스트 더블, CI/CD 연동 체계가 필요하다.

커버리지 목표는 모듈의 위험도에 맞춘다

분기, 조건, 경로, MC/DC 가운데 어떤 기준을 적용할지 먼저 정해야 한다. 중요 모듈에는 MC/DC를 적용하고 일반 모듈에는 Branch 기준을 두는 방식으로 차이를 둘 수 있다. PR 단위의 자동 검증과 실패 임계치를 품질 게이트에 연결하면 회귀가 병합되는 것을 막을 수 있다.

테스트 케이스는 Basis Path, Data Flow(Def-Use), 경계값과 오류 경로를 중심으로 설계한다. Cyclomatic Complexity는 필요한 최소 케이스를 판단하는 근거가 된다. 뮤테이션 테스트를 함께 사용하면 살아남은 돌연변이를 통해 빠진 검증을 찾아 보완할 수 있다.

JaCoCo(JVM), coverage.py(Python), Istanbul(JS) 같은 도구는 계측과 리포팅에 사용할 수 있다. HTML, LCOV, Junit XML 아티팩트를 만들고, 빌드 단계에서 계측한 뒤 테스트 실행, 커버리지 검사, 게이트 판정으로 이어지는 흐름을 구성한다.

외부 네트워크나 DB 의존성은 격리해야 한다. Stub, Mock, Spy를 사용하면 실행을 결정적(Deterministic)으로 유지할 수 있다. 트랜잭션과 락을 다루는 코드라면 격리 수준, 롤백 시나리오, 동시성 제어 흐름도 테스트 범위에 포함한다.

리포트에는 파일·모듈별 커버리지와 미실행 라인·분기를 남긴다. 복잡도(CCN)를 함께 보면 위험 우선순위를 정하기 쉽다. 플래키(Flaky) 테스트는 검출해 격리하고, 변동성이 높은 테스트에는 재시도·시간 제한·타임아웃 기준을 적용한다.

계측부터 품질 게이트까지 이어지는 흐름

전처리경로·의존 파악스텁·목 구성로그·계측 데이터 수집아니오수정 반영 재실행아니오반복 수행입력: 소스 코드, 테스트기준(예: 분기 80%), 변경 내역처리: 계측(커버리지), 정적분석, 경로 식별처리: 테스트 케이스설계·생성(기저 경로, 데이터흐름, 경계값)처리: 테스트 실행 결과수집(트랜잭션·락 시나리오포함)조건: 실패·예외 발생 여부처리: 원인 분석 수정,순서·롤백·일관성 검증조건: 커버리지가 목표치이상인지 여부처리: 테스트 보강 또는 코드리팩토링(복잡도 감소)출력: 커버리지·결함 리포트,이슈 티켓, 품질 게이트 결과

실패가 발생하면 로직 결함, 의존성, 시간 의존 가운데 원인을 분류한다. 락 순서에 따른 교착 가능성을 확인하고 트랜잭션 롤백 경로도 검증한다. 격리 수준 전제(예: READ COMMITTED)를 명시한 뒤 커밋·롤백 이후 상태와 이드포턴시 경로를 확인하는 흐름이 필요하다.

내부 구조를 아는 정도에 따른 테스트 방식

항목 화이트박스 블랙박스 그레이박스
성능(결함 탐지 효율) 내부 경로·예외 검출 우수 요구사항 위반 검출 우수 균형 잡힌 검출
확장성(대규모 코드) 커버리지 유지 비용 증가 스펙 기반으로 확장 용이 중간 수준
일관성(재현성) 높은 재현성, 의존성 격리에 좌우 환경 의존도 높음 중간 수준
안정성(변경 영향 감지) 회귀 감지 강함 간접 감지 중간 수준
운영 편의(도구/역량) 도구·코드 이해 필요 도구 부담 낮음 중간 수준

규제 영역과 변경이 잦은 시스템에서의 활용

항공·자동차 제어 로직에서는 MC/DC를 적용하고, 안전 요구 추적성과 커버리지 증빙 산출물을 관리할 수 있다. 결함 주입 시나리오는 Fail-safe와 Fault-tolerant 경로를 확인하는 데 사용된다.

금융·결제 시스템에서는 이체 한도, 승인, 롤백 분기를 검증한다. 데드락 재현 테스트로 락 순서 불변식을 확인하고, 장애 시 보상 트랜잭션(Saga) 경로를 자동 테스트 대상으로 둘 수 있다.

마이크로서비스 환경에서는 PR 빌드에서 JaCoCo 또는 coverage.py로 분기 커버리지 80~90% 게이트를 운영한다. 변경 라인(Line diff)을 기준으로 증분 커버리지를 검사하면 비용을 최적화할 수 있다.

레거시 코드 리팩토링에서는 골든 마스터 스냅샷을 만들고 기준 출력과 비교하는 테스트로 변경 위험을 낮춘다. 복잡도가 높은 모듈을 우선 대상으로 삼아 커버리지 상승과 복잡도 하향을 함께 관리한다.

Python에서 coverage.py로 검증하기

Python 3.11+, coverage.py 7.x와 pytest 또는 unittest를 전제로 한다.

pip install "coverage>=7.4,<8"

fee.py 예제는 금액과 VIP 여부에 따라 수수료를 계산하고, 음수 금액은 예외로 처리한다.

# Python 3.11
def calc_fee(amount: int, is_vip: bool) -> int:
    if amount < 0:
        raise ValueError("amount must be non-negative")
    fee_rate = 0.05 if is_vip else 0.10
    discount = 0.02 if amount > 100_000 else 0.0
    return int(amount * max(fee_rate - discount, 0.0))

테스트는 할인 경로, 일반 경로, 예외 경로를 각각 실행한다.

import unittest
from fee import calc_fee

class TestCalcFee(unittest.TestCase):
    def test_vip_large_amount_discount(self):
        self.assertEqual(calc_fee(120_000, True), int(120_000 * 0.03))

    def test_non_vip_small_amount(self):
        self.assertEqual(calc_fee(10_000, False), int(10_000 * 0.10))

    def test_negative_amount_raises(self):
        with self.assertRaises(ValueError):
            calc_fee(-1, False)

if __name__ == "__main__":
    unittest.main()

다음 명령으로 테스트를 실행하고 커버리지 게이트를 적용한다.

coverage run -m unittest discover -v
coverage report --fail-under=90
coverage html  # HTML 리포트(Optional)

Java 빌드에 JaCoCo 게이트 연결하기

JDK 17, Maven 3.9+, JaCoCo 0.8.x 환경에서 pom.xml에 다음 설정을 추가한다.

<build>
  <plugins>
    <plugin>
      <groupId>org.jacoco</groupId>
      <artifactId>jacoco-maven-plugin</artifactId>
      <version>0.8.11</version>
      <executions>
        <execution>
          <goals>
            <goal>prepare-agent</goal>
          </goals>
        </execution>
        <execution>
          <id>report</id>
          <phase>test</phase>
          <goals>
            <goal>report</goal>
          </goals>
        </execution>
        <execution>
          <id>check</id>
          <goals>
            <goal>check</goal>
          </goals>
          <configuration>
            <rules>
              <rule>
                <element>BUNDLE</element>
                <limits>
                  <limit>
                    <counter>BRANCH</counter>
                    <value>COVEREDRATIO</value>
                    <minimum>0.85</minimum>
                  </limit>
                </limits>
              </rule>
            </rules>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>
mvn -q clean test

커버리지 지표를 운영 지표로 연결할 때

화이트박스 테스트는 결함을 이르게 발견하고 회귀를 차단하는 데 쓰인다. 변경 라인을 기준으로 증분 커버리지를 관리하면 테스트 비용을 줄일 수 있다.

복잡도(CCN)와 커버리지를 결합한 지표는 위험 기반 품질 관리의 우선순위를 정하는 데 도움이 된다. 품질 게이트를 통한 자동 의사결정은 배포 안정성을 높이고 릴리스 실패율을 낮춘다. 커버리지와 추적성 리포트는 감사·컴플라이언스 증빙 자동화에도 활용된다.

운영 목표로는 분기 커버리지 80~90%, 중요 모듈의 MC/DC 목표, 플래키 테스트 비율 < 2% 목표를 둘 수 있다. 내부 구조를 기준으로 한 정량 관리와 자동화된 게이트를 바탕으로, 중요 경로부터 커버리지 기준 정의·계측·리포팅·테스트 더블 체계화를 단계적으로 확산한다.

화이트박스 테스트코드 커버리지테스트 자동화MC/DC품질 게이트