1

我一直在使用 PhpUnit,效果很好,只用断言测试我的代码。最近我决定尝试使用 PhpUnit 进行覆盖率报告分析,但我注意到使用 dataProvider 方法的测试往往会降低我的代码覆盖率分数。我想知道我可能做错了什么,或者这是否是 dataProvider 测试技术的结果?我正在使用 PhpUnit 6 和 Php 7。

我已经包含了一个源类 Foo,下面有三个测试类来测试它。FooTest 使用常规测试方法,没有 dataProviders。BarTest 使用带有 @codeCoverageIgnore 注释的 dataProvider 方法,而 BazTest 使用没有注释的 dataProvider 方法。

您可以看到使用 BazTest 的代码覆盖率得分是如何降低的。

phpunit 调用的终端截图。

包含所有测试类的代码覆盖率报告屏幕截图。

带有 BazTest 详细信息的代码覆盖率报告屏幕截图。

Foo.php

namespace phpunittestproject\src;


/**
 * Foo
 * 
 * This is a simple class to be used as a source file
 * in unit test experiments. It gets and sets a name
 * string and date object.
 *
 */
class Foo
{



    /**
     * Name
     * 
     * String characters other than numeric.
     * 
     * @var string
     */
    private $name = null;

    /**
     * Date
     * 
     * Date no older than 2000.
     * 
     * @var \DateTime
     */
    private $date = null;


    /**
     * Constructor
     * 
     * Sets instance vars.
     * 
     */
    public function __construct()
    {

        $this->name = '';
        $this->date = new \DateTime('now');

    }


    /**
     * Get Date
     * 
     * @return DateTime
     */
    public function getDate()
    {
        return $this->date;
    }

    /**
     * Get Name
     * 
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set Date
     * 
     * This method accepts a DateTime object that corresponds
     * to a date no earlier than 2000.
     * 
     * @param \DateTime $value Date after 2000.
     * @return boolean Result of operation.
     */
    public function setDate(\DateTime $value)
    {
        if($value < new \DateTime('2000-01-01 00:00:00')){
            return false;
        } else {
            $this->date = $value;
            return true;
        }
    }

    /**
     * Set Name
     * 
     * This method accepts a string that does not contain numeric
     * characters.
     * 
     * @param string $value String without numeric characters.
     * @return boolean Result of operation.
     */
    public function setName(string $value)
    {
        if(preg_match('/\\d/', $value)){
            return false;
        } else {
            $this->name = $value;
            return true;
        }
    }

}

FooTest.php:

declare(strict_types = 1);

namespace phpunittestproject\test;

use \phpunittestproject\src\Foo;

/**
 * 
 * Foo Test
 * 
 * This test class does not use dataProvider methods. All
 * test assertions are being done in test metods.
 *
 */
class FooTest extends \PHPUnit\Framework\TestCase
{


    /**
     * 
     * 
     */
    public function testGetDate()
    {
        $foo = new Foo();

        // Good date:
        $date = new \DateTime('2011-01-01 11:11:11');
        $foo->setDate($date);
        $this->assertEquals($date, $foo->getDate());

        // Bad date:
        $date = new \DateTime('1990-01-01 11:11:11');
        $foo->setDate($date);
        $this->assertNotEquals($date, $foo->getDate());

    }

    /**
     *
     * 
     */
    public function testGetName()
    {
        $foo = new Foo();

        // Good name:
        $foo->setName('A Good Name');
        $this->assertEquals('A Good Name', $foo->getName());

        // Bad name:
        $foo->setName('Bad Name 666');
        $this->assertNotEquals('Bad Name 666', $foo->getName());

    }

    /**
     * Test setDate()
     * 
     * This test method tests the date property when it is
     * set with good and bad data using method setDate().
     * 
     */
    public function testSetDate()
    {
        $foo = new Foo();

        // Good date:
        $date = new \DateTime('2011-01-01 11:11:11');
        $foo->setDate($date);
        $this->assertAttributeEquals($date, 'date', $foo);

        // Bad date:
        $date = new \DateTime('1990-01-01 11:11:11');
        $foo->setDate($date);
        $this->assertAttributeNotEquals($date, 'date', $foo);

    }

    /**
     *
     * Test setName()
     * 
     * This test method tests the name property when it is
     * set with good and bad data using method setName().
     * 
     * 
     */
    public function testSetName()
    {
        $foo = new Foo();

        // Good name:
        $foo->setName('Good Name');
        $this->assertAttributeEquals('Good Name', 'name', $foo);

        // Bad name:
        $foo->setName('Bad Name 666');
        $this->assertAttributeNotEquals('', 'name', $foo);

    }

}

BarTest.php:

declare(strict_types = 1);

namespace phpunittestproject\test;

use \phpunittestproject\src\Foo;

/**
 * 
 * Bar Test
 * 
 * This test class utilizes dataProvider methods to feed
 * test methods. The dataProvider methods are annotated
 * with codeCoverageIgnore.
 * 
 */
class BarTest extends \PHPUnit\Framework\TestCase
{


    /**
     * 
     * @codeCoverageIgnore
     */
    public function providerTestSetDateWithInvalidData()
    {
        return array(
                array(new \DateTime('1990-01-01 11:11:11')),
        );
    }

    /**
     *
     * @codeCoverageIgnore
     */
    public function providerTestSetDateWithValidData()
    {
        return array(
                array(new \DateTime('2011-01-01 11:11:11')),
        );
    }

    /**
     *
     * @codeCoverageIgnore
     */
    public function providerTestSetNameWithInvalidData()
    {
        return array(
                array('Bad Name 666'),              
        );
    }

    /**
     *
     * @codeCoverageIgnore
     */
    public function providerTestSetNameWithValidData()
    {
        return array(
                array('Good Name'),
        );
    }

    /**
     * 
     * 
     */
    public function testGetDate()
    {
        $foo = new Foo();
        $date = new \DateTime('2001-01-01 11:11:11');
        $foo->setDate($date);
        $this->assertEquals($date, $foo->getDate());
    }

    /**
     *
     * 
     */
    public function testGetName()
    {
        $foo = new Foo();
        $foo->setName('A Good Name');
        $this->assertEquals('A Good Name', $foo->getName());
    }

    /**
     *
     * @dataProvider providerTestSetDateWithInvalidData
     * 
     * 
     */
    public function testSetDateWithInvalidData($value)
    {
        $foo = new Foo();
        $foo->setDate($value);
        $this->assertAttributeNotEquals($value, 'date', $foo);
    }

    /**
     *
     * @dataProvider providerTestSetDateWithValidData
     *
     *
     */
    public function testSetDateWithValidData($value)
    {
        $foo = new Foo();
        $foo->setDate($value);
        $this->assertAttributeEquals($value, 'date', $foo);
    }

    /**
     *
     * @dataProvider providerTestSetNameWithInvalidData
     * 
     * 
     */
    public function testSetNameWithInvalidData($value)
    {
        $foo = new Foo();
        $foo->setName($value);
        $this->assertAttributeNotEquals($value, 'name', $foo);
    }

    /**
     *
     * @dataProvider providerTestSetNameWithValidData
     *
     *
     */
    public function testSetNameWithValidData($value)
    {
        $foo = new Foo();
        $foo->setName($value);
        $this->assertAttributeEquals($value, 'name', $foo);
    }

}

BazTest.php:

declare(strict_types = 1);

namespace phpunittestproject\test;

use \phpunittestproject\src\Foo;


/**
 * 
 * Baz Test
 * 
 * This test class utilizes dataProvider methods to feed
 * test methods. The dataProvider methods are not annotated
 * with codeCoverageIgnore.
 *
 */
class BazTest extends \PHPUnit\Framework\TestCase
{


    /**
     * 
     * 
     */
    public function providerTestSetDateWithInvalidData()
    {
        return array(
                array(new \DateTime('1990-01-01 11:11:11')),
        );
    }

    /**
     *
     * 
     */
    public function providerTestSetDateWithValidData()
    {
        return array(
                array(new \DateTime('2011-01-01 11:11:11')),
        );
    }

    /**
     *
     * 
     */
    public function providerTestSetNameWithInvalidData()
    {
        return array(
                array('Bad Name 666'),              
        );
    }

    /**
     *
     * 
     */
    public function providerTestSetNameWithValidData()
    {
        return array(
                array('Good Name'),
        );
    }

    /**
     * 
     * 
     */
    public function testGetDate()
    {
        $foo = new Foo();
        $date = new \DateTime('2001-01-01 11:11:11');
        $foo->setDate($date);
        $this->assertEquals($date, $foo->getDate());
    }

    /**
     *
     * 
     */
    public function testGetName()
    {
        $foo = new Foo();
        $foo->setName('A Good Name');
        $this->assertEquals('A Good Name', $foo->getName());
    }

    /**
     *
     * @dataProvider providerTestSetDateWithInvalidData
     * 
     * 
     */
    public function testSetDateWithInvalidData($value)
    {
        $foo = new Foo();
        $foo->setDate($value);
        $this->assertAttributeNotEquals($value, 'date', $foo);
    }

    /**
     *
     * @dataProvider providerTestSetDateWithValidData
     *
     *
     */
    public function testSetDateWithValidData($value)
    {
        $foo = new Foo();
        $foo->setDate($value);
        $this->assertAttributeEquals($value, 'date', $foo);
    }

    /**
     *
     * @dataProvider providerTestSetNameWithInvalidData
     * 
     * 
     */
    public function testSetNameWithInvalidData($value)
    {
        $foo = new Foo();
        $foo->setName($value);
        $this->assertAttributeNotEquals($value, 'name', $foo);
    }

    /**
     *
     * @dataProvider providerTestSetNameWithValidData
     *
     *
     */
    public function testSetNameWithValidData($value)
    {
        $foo = new Foo();
        $foo->setName($value);
        $this->assertAttributeEquals($value, 'name', $foo);
    }

}

phpunit.xml:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true" bootstrap="./vendor/autoload.php">
    <testsuites>
        <testsuite name="DataProviderTestSuite">
            <file>phpunittestproject/test/FooTest.php</file>
            <file>phpunittestproject/test/BarTest.php</file>
            <file>phpunittestproject/test/BazTest.php</file>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist>
            <file>phpunittestproject/test/FooTest.php</file>
            <file>phpunittestproject/test/BarTest.php</file>
            <file>phpunittestproject/test/BazTest.php</file>
        </whitelist>
    </filter>
</phpunit>
4

1 回答 1

1

感谢@Christopher 的解决方案!配置错误的 phpunit.xml 文件导致 PhpUnit 测试测试。编辑白名单元素修复了低代码覆盖率分数。dataProvider 方法不需要用@codeCoverageIgnore 注释!

<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true" bootstrap="./vendor/autoload.php">
    <testsuites>
        <testsuite name="DataProviderTestSuite">
            <!-- Test files go here: -->
            <file>phpunittestproject/test/FooTest.php</file>
            <file>phpunittestproject/test/BarTest.php</file>
            <file>phpunittestproject/test/BazTest.php</file>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist>
            <!-- Source files to be tested go here: -->
            <file>phpunittestproject/src/Foo.php</file>
        </whitelist>
    </filter>
</phpunit>

得分为 100% 的代码覆盖率 HTML 报告。

于 2017-04-05T01:46:30.713 回答