PHPUnit beyond basics: configuration

Feb 19, 2021·
Gert de Pagter
Gert de Pagter
· 4 min read

If you just got started with PHPUnit, its configuration file may be a bit daunting. Today we’re gonna walk through (what i consider) the ideal config file. If you’re just here to copy paste the config, then you can find it at thebottom 👇.

A minimum phpunit.xml may look like this:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit>
  <testsuites>
    <testsuite name="Tests">
      <directory>tests/</directory>
    </testsuite>
  </testsuites>
</phpunit>

The first thing we can do to improve this, is link the xsd. By doing so we now get auto completion, and validation of our xml file. If you start typing anywhere, your IDE will help you out.

<?xml version="1.0" encoding="UTF-8"?>
<phpunit
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
>
 <!--More-->
</phpunit>

PHPUnit autocomplete

PHPUnit comes with a lot of good defaults, but there are a few settings i like to set. Colors is just because i like my colors, but the other settings are important.

<phpunit
  colors= "true"
  executionOrder="random"
  failOnWarning="true"
  failOnRisky="true"
  failOnEmptyTestSuite="true"
  beStrictAboutOutputDuringTests="true"
  verbose= "true"
>
<!--More-->

By using a random execution order, we make sure our tests aren’t depending on each other. For example one test writing to a DB, and the other one is reading from it. This is bad, because then if the first test fails, the next one will too. And it may be unclear why. It also means we can’t just run the second test, as we need to run the other one first.

Fail on waring, and fail on risky will just make your test suite a bit more strict. Note that this setting is not about ’normal’ warnings, but instead warnings from phpunit. There are several reasons why phpunit may consider a test risky, which you can find here. With fail on risky we make sure those tests fail as well.

Fail on empty test suite will make sure your test suite actually contains a test. When you forget an annotation, or have a typo in your test name, then suddenly its not a test anymore, and you code may go untested, without you noticing.

Be strict about output also helps your tests be more strict. Generally, when your tests have output, that is something unintentional. Even if your code under test does an echo, you can catch that with ob_get_clean(), to validate the output of that. So any output that leaks out, should be an error.

Verbose is debatable. It does give you the most information possible on failures and errors, but if you have a test suite with a lot of skipped tests, it may be too verbose. Your best bet is to turn it on, and only if you find the output too much, turn it off.

Now that we have configured the phpunit element, there are only a few things left to do. The next thing we want to do is add some ini configurations.

<phpunit>
  <php>
    <ini name="error_reporting" value="-1"/>
    <ini name="display_errors" value="On"/>
  </php>
  <!--More-->

With error_reporting set to -1, all notices, deprecations, warnings etc, will be reported And with the default configuration, these are converted into exceptions, which mark your test failed.

Setting display_errors to On will probably not be needed for most projects. But if display_errors is off, and log_errors is too, then you will not see any error output. These are on by default in PHP, but if you, or someone who works on your project, has a wonky environment, then you won’t see any output. By forcing it to On, you will still see output of fatal errors.

Last but not least, we’ll set up our coverage:

<phpunit>
  <coverage>
    <include>
      <directory suffix=".php">src/</directory>
    </include>
  </coverage>
</phpunit

We tell phpunit that when it collects coverage, this is where to find it. Note that we don’t set a <logging> element, as that would cause phpunit to always collect coverage if possible. Instead, only pass it when it is needed. We don’t want to always generate coverage, as that will make your tests a lot slower.

Now, when you want to create a code coverage html report, you can do the following:

vendor/bin/phpunit --coverage-html=coverage
cd coverage 
php -S localhost:1313 

Now you got a nice looking code coverage report on http://localhost:1313.

TLDR

<?xml version="1.0" encoding="UTF-8"?>
<phpunit
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
  colors= "true"
  executionOrder="random"
  failOnWarning="true"
  failOnRisky="true"
  failOnEmptyTestSuite="true"
  beStrictAboutOutputDuringTests="true"
  verbose= "true"
>
  <php>
    <ini name="display_errors" value="On"/>
    <ini name="error_reporting" value="-1"/>
  </php>

  <testsuites>
    <testsuite name="Tests">
      <directory>tests/</directory>
    </testsuite>
  </testsuites>

  <coverage>
    <include>
      <directory suffix=".php">src/</directory>
    </include>
  </coverage>
</phpunit>