我一直在使用PhpUnit,結果很好,只用斷言來測試我的代碼。最近我決定嘗試使用覆蓋報告分析的PhpUnit,但我注意到使用dataProvider方法的測試往往會降低我的代碼覆蓋率。我想知道我可能會做錯什麼,或者這是否是dataProvider測試技術的後果?我正在使用PhpUnit 6和Php 7.爲什麼PhpUnit數據提供商降低覆蓋率分數?
我已經包含了一個源類Foo,下面有三個測試類來測試它。 FooTest使用常規測試方法,不使用數據提供程序。 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>
我認爲你需要從白名單中刪除測試文件。你不會在你自己的測試中做代碼覆蓋,它的意思是告訴你你的測試覆蓋了哪些應用程序代碼。 – Christopher
解決了它克里斯托弗謝謝!我編輯了phpunit.xml文件,以便將白名單文件元素替換爲單個元素' phpunittestproject/src/Foo.php '。好棒! –
peej