我一直在使用 PhpUnit,效果很好,只用断言测试我的代码。最近我决定尝试使用 PhpUnit 进行覆盖率报告分析,但我注意到使用 dataProvider 方法的测试往往会降低我的代码覆盖率分数。我想知道我可能做错了什么,或者这是否是 dataProvider 测试技术的结果?我正在使用 PhpUnit 6 和 Php 7。
我已经包含了一个源类 Foo,下面有三个测试类来测试它。FooTest 使用常规测试方法,没有 dataProviders。BarTest 使用带有 @codeCoverageIgnore 注释的 dataProvider 方法,而 BazTest 使用没有注释的 dataProvider 方法。
您可以看到使用 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>