Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Phpunit very slow when --coverage-html

Tags:

php

xml

phpunit

Im using Phpunit. If I just run my tests with:

phpunit --log-junit output.xml

this runs within a second. But if I want a code coverage:

phpunit --coverage-html ./report --log-junit output.xml

then its very slow, the phpunit sends "Configuration read from *.xml" and it hangs for a minute, then it start executing the tests

like image 966
John Smith Avatar asked Sep 05 '14 09:09

John Smith


4 Answers

By default, PHPUnit will evaluate the coverage of all files in your configured whitelist, even when you run PHPUnit for a single test.

If you have a lot files in your whitelist, this can add a LOT of time to the generation of the code coverage.

You can speed things up by configuring PHPUnit to generate code coverage only for the files you have written/execute tests for, by setting the addUncoveredFilesFromWhitelist attribute to false.

<phpunit>
    <!-- ... -->
    <filter>
        <whitelist addUncoveredFilesFromWhitelist="false">
            <!-- ... -->
        </whitelist>
    </filter>
</phpunit>

With this setting disabled, you should see that the resulting code coverage files only describe the files you ran the tests for.

Note that the PHPUnit documentation suggests addUncoveredFilesFromWhitelist is false by default, but on version 5.5 it appears to be true by default.

like image 136
Courtney Miles Avatar answered Nov 07 '22 05:11

Courtney Miles


Just to increment the last answer. Usually, it happens because PHPunit see all the files and you need to tell them to not do it, like this follow example:

Take a look to my filter node into phpunit.xml like this

<filter>
    <whitelist>
        <directory>../src</directory>
    </whitelist>
</filter>

I need to add addUncoveredFilesFromWhitelist equal to false and add all of the files which I need to exclude, like this:

<filter>
   <whitelist addUncoveredFilesFromWhitelist="false">
        <directory suffix=".php">../src</directory>
        <exclude>
            <directory>../vendor</directory>
            <directory>../anotherpath</directory>
            <directory>../src/Modules/*/Fixture</directory>
            <file>../src/Modules/*/Bootstrap.php</file>
        </exclude>
    </whitelist>
</filter>

Pay attention to my exclude list where I exclude the "Fixture" directory and Bootstrap.php file for all modules

After did this simple changes my unit tests change from 10 minutes to 3 minutes, so enjoy :)

like image 43
Paulo Victor Avatar answered Nov 07 '22 05:11

Paulo Victor


When running phpunit with code coverage, the thing that impacts the speed the most is the fact that for each test method, phpunit uses xdebug with XDEBUG_CC_UNUSED and XDEBUG_CC_DEAD_CODE, which checks for dead and unused code in every file that is touched during that particular test execution. This includes vendor classes, test classes, phpunit framework classes and any other classes outside of your whitelist. phpunit only actually cares about the subjects under test (or classes in your whitelist). I am in the process of tweaking code coverage to be smarter about running xdebug with the 2 mentioned flags on, so it only bothers checking out the dead and unused code of the files that phpunit cares about. You can check the progress here. https://github.com/sebastianbergmann/php-code-coverage/pull/387

like image 3
MajorCaiger Avatar answered Nov 07 '22 05:11

MajorCaiger


This is normal behaviour.

Think about what PHPUnit is doing:

It's running your tests, tracking every execution of every line of code, then taking all that raw data (the number of times each line was executed) and building a report by reading your code and reformatting it as HTML, supplemented with all that execution data.

It's not surprising that it takes a long time.

like image 2
Kryten Avatar answered Nov 07 '22 04:11

Kryten