I have the following function:
function foo($p)
{
if ($p == null)
throw new Exception('bla');
if ($p == null)
{
throw new Exception('bla');
}
[...]
}
My Test for this function is not covering the lines throwing the exception. But PHPUnit tells me the first 'throw'-statement is coverd, the second not. Maybe the first is interpreted, but it is not executed.
So I don't want to get the message '100%' if I have not reached 100%.
Is this a bug in xDebug or do I have the possibility to configure xDebug/PHPUnit?
xDebug's code coverage metrics are statement-based rather than line-based. What this means is that a control structure without a block enclosed in braces is treated as a single statement. To let xDebug see the throw
line as separate from the if()
test, surround it with braces as you did in the second statement.
if ($p == null) // statement 1
throw new Exception('bla'); // rest of statement 1
vs.
if ($p == null) { // statement 1
throw new Exception('bla'); // statement 2
}
This happens because xDebug can't provide better data, as it is only aware of statements and not of 'lines' and is documented in the PHPUnit documentation under:
Code coverage analysis - Edge Cases
:
<?php
// Due to how code coverage works internally these two lines are special.
// This line will show up as non executable
if(false)
// This line will show up as covered because it is actually the
// coverage of the if statement in the line above that gets shown here!
will_also_show_up_as_coveraged();
// To avoid this it is necessary that braces are used
if(false) {
this_call_will_never_show_up_as_covered();
}
The same goes for the $x ? $y : $z;
construct. The only way to avoid this behavior is to add curly braces.
Its pretty bad when you have to modify your source to overcome flaws of the tools you are using.
Our PHP Test Coverage Tool doesn't have this problem.
In addition, if you place several statements in the same line, ours will track them individually. I believe XDebug will mark the "line" as covered if any part of the first statement in the line is covered. I believe it will do this even for the following:
if (... ) { .... }
So you will get "false" coverage reported for the block controlled by the conditional, even if the conditional is always false.