Reaching 100% Code Coverage with PHPunit

Reaching 100% Code Coverage with PHPUnit

First off: 100% code coverage is a great metric to strive for. It's just not always achievable with a sane amount of effort and it's not always important to do so :)

The issue comes from xDebug telling PHPUnit that this line is executable but not covered.

For simple cases xDebug can tell that the line is NOT reachable so you get 100% code coverage there.

See the simple example below.


2nd Update

The issue is now fixed xDebug bugtracker so building a new version of xDebug will solve those issues :)

Update (see below for issues with php 5.3.x)

Since you are running PHP 5.4 and the DEV version of xDebug I've installed those and tested it. I run into the same issues as you with the same output you've commented on.

I'm not a 100% sure if the issue comes from php-code-coverage (the phpunit module) for xDebug. It might also be an issue with xDebug dev.

I've filed a bug with php-code-coverage and we'll figure out where the issue comes from.


For PHP 5.3.x issues:

For more complex cases this CAN fail.

For the code you showed all I can say is that "It works for me" (complex sample below).

Maybe update xDebug and PHPUnit Versions and try again.

I've seen it fail with current versions but it depends on how the whole class looks sometimes.

Removing ?: operators and other single-line multi-statement things might also help out.

There is ongoing refactoring in xDebug to avoid more of those cases as far as I'm aware. xDebug once wants to be able to provide "statement coverage" and that should fix a lot of those cases. For now there is not much one can do here

While //@codeCoverageIgnoreStart and //@codeCoverageIgnoreEnd will get this line "covered" it looks really ugly and is usually doing more bad than good.

For another case where this happens see the question and answers from:

what-to-do-when-project-coding-standards-conflicts-with-unit-test-code-coverage


Simple example:

<?php
class FooTest extends PHPUnit_Framework_TestCase {
public function testBar() {
$x = new Foo();
$this->assertSame(1, $x->bar());
}
}

<?php
class Foo {
public function bar() {
return 1;
}
}

produces:

phpunit --coverage-text mep.php 
PHPUnit 3.6.7 by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 3.50Mb

OK (1 test, 1 assertion)

Generating textual code coverage report, this may take a moment.

Code Coverage Report
2012-01-10 15:54:56

Summary:
Classes: 100.00% (2/2)
Methods: 100.00% (1/1)
Lines: 100.00% (1/1)

Foo
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 1/ 1)

Complex example:

<?php

require __DIR__ . '/foo.php';

class FooTest extends PHPUnit_Framework_TestCase {

public function testBar() {
$this->assertSame('b', Foo::getDomain('a'));
$this->assertInstanceOf('Config', Foo::getDomain('foo'));
}
}

<?php

class Foo {
static $domains = array('a' => 'b');

static public function &getDomain($domain = null) {
$domain = $domain ?: self::domain();
if (! array_key_exists($domain, self::$domains)) {
self::$domains[$domain] = new Config();
}
return self::$domains[$domain];
}
}

class Config {}

produces:

PHPUnit 3.6.7 by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 3.50Mb

OK (1 test, 2 assertions)

Generating textual code coverage report, this may take a moment.

Code Coverage Report
2012-01-10 15:55:55

Summary:
Classes: 100.00% (2/2)
Methods: 100.00% (1/1)
Lines: 100.00% (5/5)

Foo
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 5/ 5)

How to reach 100% code coverage with expectexception in PHPUnit

No, you wont get 100%, because metric should not be on your TEST.
You should use whitelist or blacklist in configuration, to ommit this tests.

It is mandatory to configure a whitelist for telling PHPUnit which
sourcecode files to include in the code coverage report.

<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">/path/to/files</directory>
<file>/path/to/file</file>
<exclude>
<directory suffix=".php">/path/to/files</directory>
<file>/path/to/file</file>
</exclude>
</whitelist>
</filter>

Your code will mark, that went to handleMatchResults and execute throw. In other test, you will execute positive scenario with this function.

That way you should have 100% coverage.

How to get 100% Code Coverage with PHPUnit

The code you have only comments for is what matters. The closing brace of a block will be shown as executable in the code coverage report if it's possible to fall through to the end. Look for a branch that you aren't actually testing.

if ($request->isPost()) {
if ($x < 5) {
return '<';
}
elseif ($x > 5) {
return '>';
}
// Do you have a test for $x == 5?
}

As for the 100% code coverage goal, I agree wholeheartedly with Bill. For some framework classes that I write I will strive to make 100%, but I know that doesn't mean I've truly tested every possibility. Often, when I find myself working overly hard to achieve 100% coverage, it's probably OCD kicking in. :)

Just . . . one . . . more . . . test . . .

How to made the code coverage to 100%

It's good to always have code coverage 100%. But like you said there are situations when this is very hard to achieve. So having code coverage greater than 70% is quite good for most of the projects. See this link regarding the minimum code coverage required in project. But you should try to extract your business logic to its own class (Repository) and unit test it.

PhpUnit + Symfony: Why coverage shows white instead of red and gives 100% on untested class?

Found!!

Quick solution

Update the xdebug library here: https://xdebug.org/wizard.php

Detailed solution

As you can see in the question's images, I was using the Xdebug 2.4.0 because that's the one that just was in my system, a stable Ubuntu 16.04.

As per this thread: https://github.com/sebastianbergmann/php-code-coverage/issues/411 during one full year those folks (thanks you all) they were pursuing the same problem: Lines not being reported as executable.

Finally they came to the conclusion that there was a bug in XDebug and it finally was reported and corrected.

This is: xdebug was improerply reporting data to phpunit, so phpunit was running on erroneous hypothesis.

I upgraded here https://xdebug.org/wizard.php (the link I found in that thread), and I compiled a new xdebug as instructed.

Here you can see that the project is not now 100%, but 75% in lines and 50% in classes (as expected):

Sample Image

Here you can see that the Command A reports 100% (which is okey, because it is the one I test) and Command B is reported 50% in lines and 0% in class, as expected, as I did not write a test for it. The method configure() is run on kernel boot and application loading:

Sample Image

And if we enter in Command B (ie: DummyBCommand) we can finally see that the method execute() is marked as red, not white:

Sample Image

In this image you can see in [1] that the configure() is 100% and the execute() is 0%, which is correct.

In [2] you can see the colors. execute() is marked red, as expected.

And finally, in [3] you can see that the XDebug version is the 2.5.4, the latest stable on 10/sep/2017 (or at least, the one that the update wizard suggested me to install).

So... download, configure, compile, install and boom, done!

Code Coverage with PHPUnit

If you have set up a <whitelist> in your phpunit.xml configuration file you should see all the not covered files. It might an issue with the pathes, try absolute ones to see that it creates 0% coverage for some files and then make the relative pathses work.

For combining the coverage there is not much you can to with phpunit that i know of. You could combine the coverage results (PHPUnit_Coverage package) by hand and then figure out how to render them but you'd need to do that by hand. At least i don't know of any project/tool/way that does that for you.

The easiest way would be to run all your 3 testsuites in one phpunit run and have it generate the code coverage for the parts you are about.



Related Topics



Leave a reply



Submit