SpazzMarticus
SpazzMarticus

Reputation: 1277

PHPUnit Strict Mode - setUp() - Coverage

I currently started using the strict-Mode in PHPUnit, when I came across a Problem with the code-coverage:

If I use the setUp-method to create a new instance of a my class the __constructor-method is listed in the code-coverage as covered when i run the tests.

This is my test-setup:

phpunit.config.xml

<?xml version="1.0" encoding="UTF-8"?>
<phpunit
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.5/phpunit.xsd"
    bootstrap="../vendor/autoload.php"
    backupGlobals="false"
    backupStaticAttributes="false"
    colors="true"
    verbose="true"    
    beStrictAboutOutputDuringTests="true"
    beStrictAboutTestSize="true"
    beStrictAboutTestsThatDoNotTestAnything="true"
    beStrictAboutTodoAnnotatedTests="true"

    checkForUnintentionallyCoveredCode="true"
    processIsolation="false"
>
<testsuites>
    <testsuite name="FooTests">
        <directory suffix="Test.php">../tests</directory>
    </testsuite>
</testsuites>
<filter>
    <whitelist>
        <directory suffix=".php">../src</directory>
    </whitelist>
</filter>
<logging>
    <log type="coverage-html" target="coverage/" higlight="true" showUncoveredFiles="true"></log>    
</logging>

Foo.php

class Foo
{

    protected $_bar;

    public function __construct($bar)
    {
        $this->_bar=$bar;             //Line 10
    }                                 //Line 11

    public function getBar()
    {
        return $this->_bar;
    }

    public function getBar2()
    {
        return $this->_bar;
    }

}

and the Test: FooTest.php

class FooTest extends \PHPUnit_Framework_TestCase
{

    protected $_foo;

    protected function setUp()
    {
        $this->_foo=new Foo(10);
    }

    public function testGetBar()
    {
        $this->assertSame(10, $this->_foo->getBar());
    }

    /**
     * @covers Foo::getBar2
     */
    public function testGetBar2()
    {
        $this->assertSame(10, $this->_foo->getBar2());
    }

}

If I run the tests I get this result:

PHPUnit 4.5.0 by Sebastian Bergmann and contributors.

Configuration read from C:\xampp\htdocs\unittest\build\phpunit.config.xml

.R

Time: 88 ms, Memory: 3.50Mb

There was 1 risky test:
1) FooTest::testGetBar2
This test executed code that is not listed as code to be covered or used:
- C:\xampp\htdocs\unittest\src\Foo.php:10
- C:\xampp\htdocs\unittest\src\Foo.php:11

OK, but incomplete, skipped, or risky tests!
Tests: 2, Assertions: 2, Risky: 1.

Generating code coverage report in HTML format ... done

As soon as I specify the @covers on the test the problem appears.

Is this expected behavior?

Some things I tried:

Is there a way to remove the setUp() code from the code-coverage and using @covers on tests with methods they actually test?

Edit: This also affects inheritance. So if Bar extends Foo, and passes arguments on to Foo::__construct that will be on the code-coverage too - which makes writing the @covers for the __construct a pain in the a**...

Additional info:

PHP 5.6.3 (cli) (built: Nov 12 2014 17:18:08)
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2014 Zend Technologies
with Xdebug v2.2.5, Copyright (c) 2002-2014, by Derick Rethans

Upvotes: 18

Views: 5901

Answers (3)

pablorsk
pablorsk

Reputation: 4286

On PHPUnit >= 6.0 set beStrictAboutCoversAnnotation to false on phpunit.xml:

<phpunit
     // ....     
     beStrictAboutCoversAnnotation="false"
>
// ....

Also, you can run phpunit without --strict-coverage

More info on Risky Tests: Unintentionally Covered Code

Upvotes: 2

SpazzMarticus
SpazzMarticus

Reputation: 1277

Since this question started to gain some momentum: Here is my kind-of-solution for the problem.

My unit-test (FooTest) of Foo will always use Foo, therefore I add @uses Foo to the class.

This is also important if protected/private functions are used by public functions, because else you have to add each and every protected/private function to a test, if the class uses the function internally. I even think it is wrong if you are doing unit-tests, because a unit-test must not care about how the class does "stuff", it should only assert that a specific input results in a specific output.

(Additionally: The constructor should only do assignments, nothing else.)

After adding @uses the error will disapear.

(You can add @covers Foo::_construct to the class to have code-coverage of your constructor.)

/**
 * @uses Foo 
 * (optional)@covers Foo::__construct
 */
class FooTest extends \PHPUnit_Framework_TestCase
{
    protected $_foo;

    protected function setUp()
    {
        $this->_foo=new Foo(10);
    }

    public function testGetBar()
    {
        $this->assertSame(10, $this->_foo->getBar());
    }

    /**
     * @covers Foo::getBar2
     */
    public function testGetBar2()
    {
        $this->assertSame(10, $this->_foo->getBar2());
    }
}

Upvotes: 6

qrazi
qrazi

Reputation: 1391

You have specified strict coverage with checkForUnintentionallyCoveredCode="true". And since PHPUnit 4.0 PHPUnit has the following behaviour:

Dealing with unintentionally covered code

PHPUnit 4.0 can optionally be strict about unintentionally covered code (strict > coverage mode). When enabled, PHPUnit will fail a test that uses the @covers annotation and executes code that is not specified using a @covers annotation.

Upvotes: 3

Related Questions