Setup PHP PCOV for 5 times faster PHPUnit code coverage
Tags: php, xdebug, pcov, wordpress
Published: 2019-11-08 15:06:48

---
title: Setup PHP PCOV for 5 times faster PHPUnit code coverage
published: true
description: How we can use PCOV instead of XDebug to get fast code-coverage in PHP and WordPress Projects.
tags: php, xdebug, pcov, wordpress
cover_image: https://images.unsplash.com/photo-1561444576-c102239d8cf2?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2850&q=80
---

I am a WordPress developer, and my daily tasks involves writing lots of PHP code. In my latest project, I am making a GraphQL server right inside WordPress and of course it involves testing.

For code-coverage, I use XDebug and while it works, it is painfully slow. In our GitLab CI, it takes over 30 minutes to run a complete coverage.

![PHPUnit Coverage with XDebug](https://thepracticaldev.s3.amazonaws.com/i/089z4qflm84yxwzpuofi.png)

Enter [PHP PCOV](https://github.com/krakjoe/pcov). After a complete setup, our tests finish in a little over 6 minutes. It is 5 times faster than before. 

![PHPUnit Coverage with PCOV](https://thepracticaldev.s3.amazonaws.com/i/18mssbf35uzmjge3u55y.png)

Now that you might feel convinced, let's dive in how we did that.

## Step 1: Installation

We need the PCOV extension installed and XDebug extension completely disabled. To install PCOV run

```bash
pecl install pcov
```

The above would work on most Linux and MacOS systems. If you are using official PHP docker images, then run

```bash
pecl install pcov && docker-php-ext-enable pcov
```

Make sure to remove XDebug as well. On docker, simply don't install XDebug extension. On other system, edit `php.ini` file and remove or comment the line with `extension="xdebug.so"`.

## Step 2: Clobber PHPUnit version 7 or less

PCOV has built-in support for PHPUnit version 8 or greater. But I am stuck with PHPUnit 7, because I need the full WordPress testing library which currently works only with PHPUnit 7. Luckily [Joe Watkins](https://blog.krakjoe.ninja/) the same person who made PCOV has also made a package called [PCOV Clobber](https://github.com/krakjoe/pcov-clobber), for exactly this.

At this point, I am assuming you are using PHPUnit as a composer dependency. So run

```bash
composer require pcov/clobber --dev
```

followed by

```bash
vendor/bin/pcov clobber
```

This will make changes to the existing files inside `vendor` directory to make XDebug drive use PCOV instead.

**Note**: You have to run this command every-time you update any composer package.

## Step 3: Run PHPUnit with PCOV

Now at this point, if you simply run

```bash
./vendor/bin/phpunit
```

chances are, you will be given empty code coverage (unless your source files are inside `src`, `lib` or `app` directory. So we have to make changes to some configuration variable while running PHPUnit. Simply run the following command and it should just work

```bash
php -dpcov.enabled=1 -dpcov.directory=. -dpcov.exclude="~vendor~" ./vendor/bin/phpunit --coverage-text
```

Thanks to Ahmet Bora at [this github issue](https://github.com/krakjoe/pcov/issues/34) to figure this out. Here's what's happening

* `pcov.enabled=1` - Enable PCOV support.
* `pcov.directory=.` - Get coverage for all files in current directory.
* `pcov.exclude="~vendor~"` - Exclude coverage for `vendor` directory.

## Bonus: GitLab CI Configuration

Since we run our tests mostly in CI, and we use [GitLab](https://gitlab.com), here's how our `.gitlab-ci.yml` file looks like.

```yml
test:php73:
  stage: test
  tags:
    - wordpress
  image: registry.gitlab.com/wpquark/docker-containers/php-node:2.0.0-php-7.3-node-12.13.0
  services:
    - mariadb:10.3
  before_script:
    - yarn install --frozen-lockfile
    - composer install
    - vendor/bin/pcov clobber
  script:
    # - yarn phpunit
    - php -dpcov.enabled=1 -dpcov.directory=. -dpcov.exclude="~vendor~" ./vendor/bin/phpunit --configuration=phpunit.ci.xml --testdox
  artifacts:
    paths:
      - coverage/phpunit
    expire_in: 2 days
```

The thing to notice is we do `vendor/bin/pcov clobber` before running the `phpunit` command.

Also here's the content of `phpunit.ci.xml`

```xml
<?xml version="1.0"?>
<phpunit
	bootstrap="tests/bootstrap.php"
	backupGlobals="false"
	colors="true"
	convertErrorsToExceptions="true"
	convertNoticesToExceptions="true"
	convertWarningsToExceptions="true"
	verbose="true"
	>
	<testsuites>
		<testsuite name="Unit Tests">
			<directory suffix="Test.php">./tests/Unit/*</directory>
		</testsuite>
		<testsuite name="Integration Tests">
			<directory suffix="Test.php">./tests/Integration/*</directory>
		</testsuite>
		<testsuite name="GraphQL Tests">
			<directory suffix="Test.php">./tests/GraphQL/*</directory>
		</testsuite>
	</testsuites>
	<filter>
		<whitelist processUncoveredFilesFromWhitelist="false">
			<directory suffix=".php">./inc</directory>
			<exclude>
				<directory suffix=".php">./inc/System</directory>
				<directory suffix=".php">./inc/View</directory>
			</exclude>
		</whitelist>
	</filter>
	<logging>
		<log type="coverage-text" target="php://stdout" showUncoveredFiles="true"/>
		<log type="coverage-clover" target="coverage/phpunit/clover.xml" showUncoveredFiles="true"/>
		<log type="coverage-html" target="coverage/phpunit/html" lowUpperBound="35" highLowerBound="70"/>
	</logging>
</phpunit>

```

---

I hope you will give PCOV a try. Also give a huge shout-out to [@krakjoe](https://twitter.com/krakjoe) who made all these things possible.