9. Code Coverage Analysis

    In this chapter you will learn all about PHPUnit’s code coverage functionality that provides an insight into what parts of the production code are executed when the tests are run. It makes use of the php-code-coverage component, which in turn leverages the code coverage functionality provided by the or PCOV extensions for PHP or by .

    Note

    If you see a warning while running tests that no code coverage driver is available, it means that you are using the PHP CLI binary () and do not have Xdebug or PCOV loaded.

    PHPUnit can generate an HTML-based code coverage report as well as XML-based logfiles with code coverage information in various formats (Clover, Cobertura, Crap4J, PHPUnit). Code coverage information can also be reported as text (and printed to STDOUT) and exported as PHP code for further processing.

    Please refer to The Command-Line Test Runner for a list of command line switches that control code coverage functionality as well as for the relevant configuration settings.

    Various software metrics exist to measure code coverage:

    Line Coverage

    The Line Coverage software metric measures whether each executable line was executed.

    Branch Coverage

    Path Coverage

    Function and Method Coverage

    Class and Trait Coverage

    The Class and Trait Coverage software metric measures whether each method of a class or trait is covered. php-code-coverage only considers a class or trait as covered when all of its methods are covered.

    Change Risk Anti-Patterns (CRAP) Index

    It is mandatory to configure a filter for telling PHPUnit which sourcecode files to include in the code coverage report. This can either be done using the --coverage-filter command line option or via the configuration file (see ).

    The includeUncoveredFiles and processUncoveredFiles configuration settings are available to configure how the filter is used:

    • (default) means that all files are included in the code coverage report even if not a single line of code of such a file is executed

    • processUncoveredFiles="false" (default) means that a file that has no executed lines of code will be added to the code coverage report (if includeUncoveredFiles="true" is set) but it will not be loaded by PHPUnit and it will therefore not be analysed for correct executable lines of code information

    Please note that the loading of sourcecode files that is performed when processUncoveredFiles="true" is set can cause problems when a sourcecode file contains code outside the scope of a class or function, for instance.

    Sometimes you have blocks of code that you cannot test and that you may want to ignore during code coverage analysis. PHPUnit lets you do this using the @codeCoverageIgnore, @codeCoverageIgnoreStart and annotations as shown in .

    Example 9.1 Using the @codeCoverageIgnore, @codeCoverageIgnoreStart and @codeCoverageIgnoreEnd annotations

    The ignored lines of code (marked as ignored using the annotations) are counted as executed (if they are executable) and will not be highlighted.

    The @covers annotation (see the ) can be used in the test code to specify which code parts a test class (or test method) wants to test. If provided, this effectively filters the code coverage report to include executed code from the referenced code parts only. Example 9.2 shows an example.

    Note

    If a method is specified with the @covers annotation, only the referenced method will be considered as covered, but not methods called by this method. Hence, when a covered method is refactored using the extract method refactoring, corresponding @covers annotations need to be added. This is the reason it is recommended to use this annotation with class scope, not with method scope.

    Example 9.2 Test class that specifies which class it wants to cover

    Example 9.3 Tests that specify which method they want to cover

    It is also possible to specify that a test should not cover any method by using the annotation (see ). This can be helpful when writing integration tests to make sure you only generate code coverage with unit tests.

    Example 9.4 A test that specifies that no method should be covered

    This section shows noteworthy edge cases that lead to confusing code coverage information.