Skip to content

Code Coverage

When your Unit Tests are run, PHPUnit can keep track of which lines of application code have been run. The objective of this is to show how much of your code has actually been tested. If you have all tests passing, but not all of your code has been run, there's a risk that bugs exist which your tests don't check for.

When you run your tests with coverage, PHPUnit generates a set of HTML pages which show what has and hasn't been covered by your tests, giving a percentage overview for each file, and line-by-line detail within each file.

You must have at least 50% coverage, and should aim to be above the 90% coverage threshold.

Coverage requires xdebug to be installed an enabled.

Adding Coverage for the class

PHPUnit needs to know which application class each test class is attempting to cover.

Class-level coverage

For Bronze and Silver test levels, you should add a class-level @covers declaration

 /**
 * @covers \App\Maths\Addition
 */
 class AdditionTest extends \PHPUnit\Framework\TestCase
 {

Generally only Small and Medium tests should be covered. Large tests should use a class-level @coversNothing annotation. This test class will then be omitted from any coverage reports.

Method-level coverage

For the Gold test level we require per-method coverage. This comes in two parts:

  • On the class level, a @coversDefaultClass annotation specifies which class is being referenced in the method-level @covers annotations
  • On the method level, a @covers annotation specifies which Application method is being tested. You can add multiple of these per test method
/**
 * @coversDefaultClass \App\Scraper\Page
 */
class PageTest extends TestCase
{

    /**
     * @test
     * @covers ::getUrl()
     */
    public function pageIsCreatedWithUrl()
    {
        ...

    /**
     * @test
     * @covers ::getPrice()
     */
    public function throwsExceptionBeforeDownload()
    {
    ...

Configuration

To omit coverage from your test run (to speed things up), you can run PHPUnit without Xdebug, or at least pass --no-coverage.

Further Reading