PHPUnit으로 단위 테스트를 작성하고 코드 커버리지(Code Coverage)를 측정할 때, 테스트 실행 시간이 터무니없이 길어져 지루하게 기다린 경험이 있을 것이다.
다만 대부분의 개발자들은 이 병목의 원인이 Xdebug의 디버깅 오버헤드 때문이라는 점과 이를 대체할 수 있는 전용 라이브러리가 존재한다는 사실을 잘 모른다.
이번에는 PHPUnit 커버리지 측정 시 발생하는 속도 저하의 원인이 정확히 뭔지, 왜 PCOV가 필요한지, 그리고 실제 환경에서 어떻게 설정하고 적용하는지 완벽하게 정리해서 소개하겠다.

 

Xdebug 코드 커버리지의 병목 원인과 PCOV의 등장

PHPUnit에서 테스트 커버리지를 출력하려면 코드 실행 경로를 추적하는 드라이버가 필요하다. 오랫동안 PHP 생태계에서는 Xdebug를 기본 드라이버로 사용해 왔다.
Xdebug는 브레이크포인트 설정, 변수 추적, 함수 호출 스택 분석 등 정교한 디버깅 기능을 제공하는 훌륭한 도구다. 그러나 코드 커버리지 하나만을 측정하기에는 너무 무겁다. 실행 시점마다 메모리와 CPU 연산 오버헤드가 크게 발생하기 때문이다.

테스트 코드가 수백, 수천 개로 늘어나면 Xdebug 기반 커버리지 측정은 몇 분 이상 걸리기 일수다. 반면 PCOV(PHP Code Coverage Extension)는 오직 커버리지 측정만을 위해 설계된 C 확장 모듈이다. 디버깅 전용 기능을 모두 제거하고 코드 실행 라인 추적에만 집중하기 때문에 Xdebug 대비 최소 5배에서 최대 10배 이상 빠른 실행 속도를 보여준다.

 

Xdebug vs PCOV 기능 비교
구분XdebugPCOV
주요 목적단계별 디버깅, 프로파일링, 커버리지코드 커버리지 전용 측정
실행 오버헤드매우 높음 (테스트 대폭 지연)극히 낮음 (네이티브 실행에 가까움)
설정 복잡도다양한 옵션으로 복잡함최소한의 기동 옵션만 존재
PHP 버전 지원PHP 7.0 이상PHP 7.1 이상 (PHP 8.x 완벽 지원)

 

PCOV 설치 및 php.ini 환경 설정

PCOV는 PECL을 통해 손쉽게 설치할 수 있다. 먼저 시스템에 설치된 PHP 버전과 개발 도구가 준비되어 있어야 한다.

 

Linux (Ubuntu/Debian) 및 macOS 환경 설치

터미널에서 PECL 명령어로 PCOV 모듈을 컴파일하고 설치한다.

# PECL을 통한 PCOV 설치
sudo pecl install pcov

# 설치 완료 후 extension 등록 확인
php -m | grep pcov

설치가 완료되면 php.ini 파일에 PCOV 설정을 추가해야 한다. CLI 환경의 php.ini 위치를 확인한 뒤 아래 구문을 추가하자.

; php.ini 설정
extension=pcov.so

; PCOV 활성화 및 탐색 경로 지정
pcov.enabled = 1
pcov.directory = ./src
pcov.exclude = ./vendor

pcov.directory 옵션은 커버리지를 측정할 실제 소스 코드 디렉터리를 지정한다. 이 값을 올바르게 설정해야 vendor 라이브러리나 테스트 파일 자체를 추적 대상에서 제외하여 측정 속도를 극대화할 수 있다.

 

PHPUnit과 PCOV 실전 연동 예제

이제 PHPUnit 환경에서 PCOV를 활용해 코드 커버리지 리포트를 생성해보자.
많은 개발자들이 겪는 실수 중 하나는 Xdebug 모듈이 켜진 상태에서 그대로 커버리지를 실행하는 것이다. 드라이버 충돌이 발생하거나 Xdebug가 우선권을 가져가 여전히 느린 속도로 실행될 수 있다.

 

✗ 잘못된 실행 방법 (Xdebug 오버헤드 포함)

✗ php.ini에 Xdebug가 활성화된 상태에서 PHPUnit 커버리지를 그대로 실행하면 Xdebug 드라이버가 동작하여 속도 개선 효과를 전혀 보지 못한다.

# Xdebug가 켜진 상태로 실행 (매우 느림)
php -d xdebug.mode=coverage ./vendor/bin/phpunit --coverage-html build/coverage

실행 결과: 테스트 100개 기준 약 12.4초 소요.

 

✓ 올바른 실행 방법 (PCOV 명시적 적용)

✓ Xdebug 모듈을 비활성화하거나 xdebug.mode를 off로 두고, PCOV를 활성화하여 PHPUnit을 실행한다.

# Xdebug 끄고 PCOV 드라이버로 커버리지 리포트 생성
php -d xdebug.mode=off -d pcov.enabled=1 ./vendor/bin/phpunit --coverage-html build/coverage

실행 결과: 테스트 100개 기준 약 0.8초 소요 (약 15배 성능 향상).

 

phpunit.xml 구성 예시

PHPUnit 9 이상 버전에서는 phpunit.xml 설정 파일에 분석 대상 소스 코드 디렉터리를 명확히 기재해야 PCOV가 정확하게 작동한다.

<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"
         bootstrap="vendor/autoload.php"
         colors="true">
    <testsuites>
        <testsuite name="Unit">
            <directory>tests/Unit</directory>
        </testsuite>
    </testsuites>

    <!-- 코드 커버리지 대상 설정 -->
    <coverage processUncoveredFiles="true">
        <include>
            <directory suffix=".php">src</directory>
        </include>
        <exclude>
            <directory>src/Migrations</directory>
        </exclude>
    </coverage>
</phpunit>

 

주의사항 및 흔한 실수 패턴

PCOV 적용 시 실무에서 자주 부딪히는 문제들을 파악해두면 쓸데없는 시간 낭비를 줄일 수 있다.

✗ pcov.directory 설정 누락
pcov.directory를 지정하지 않거나 .(현재 디렉터리) 전체로 지정하면 vendor 폴더 안의 무수한 외부 라이브러리까지 스캔한다. 결과적으로 커버리지 생성 속도가 다시 느려지거나 메모리 부족 에러가 발생한다.
✓ 해결책: 프로젝트의 실제 비즈니스 로직이 들어있는 src 또는 app 디렉터리로 범위를 좁혀라.

✗ Xdebug와 PCOV의 동시 활성화
두 확장이 동시에 로드되어 켜져 있으면 상호 간섭으로 인해 원인 모를 경고(Warning) 메시지가 출력되거나 측정 결과가 왜곡될 수 있다.
✓ 해결책: CI/CD 파이프라인이나 개발 환경 스크립트에서 커버리지 측정 시에는 반드시 xdebug.mode=off 옵션을 명시적으로 전달하라.

 

핵심 요약 및 향후 과제

테스트 커버리지 측정 속도는 CI/CD 빌드 타임과 개발 생산성에 직결되는 중요한 요소다. 디버깅 기능이 필요할 때는 Xdebug를 쓰고, 빠른 테스트 실행과 커버리지 측정 시에는 PCOV를 사용하는 분리가 필요하다.
작은 최적화와 올바른 도구 선택이 모여 전체 배포 속도와 개발 경험을 크게 바꾼다는 점을 잊지 말자. 이 글의 PCOV 설정 및 실행 명령어를 참고해 프로젝트에 적용하면, 몇 분씩 걸리던 커버리지 측정을 몇 초 만에 끝낼 수 있을 것이다.