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):
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:
And if we enter in Command B (ie: DummyBCommand
) we can finally see that the method execute()
is marked as red, not white:
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
Error Building:Fatal Error: Pcre.H: No Such File or Directory
How to Force Doctrine to Update Array Type Fields
Sort an Array with Special Characters in PHP
Require_Once () or Die() Not Working
How to Reuse Deleted Primary Keys in MySQL
Using SQLite3 in PHP How to Count the Number of Rows in a Result Set
Make a Https Request Through PHP and Get Response
How to Post Button Value to PHP
PHP Get Content of Http 400 Response
Php: Get List of All Filenames Contained Within My Images Directory
How to Access a Different Controller from Inside a Controller Symfony2
Laravel Quick Start Guide Route Not Working
Move All Files in a Folder to Another
PHP Dom Get Nodevalue HTML? (Without Stripping Tags)
Browser Displays � Instead of '
Rsa Encryption/Decryption Compatible with JavaScript and PHP