PHP 函数在多次调用时未报告为 PHP 单元完全覆盖
PHP function not reported as completely covered by PHPUnit when calling multiple times
有人可以解释为什么以下功能没有报告为 phpUnit 完全涵盖吗?
或者更好的是,解释如何将其报告为完全覆盖?
function itDoesThingsToValue()
{
static $value = -1;
if ($value < 0) {
$value = 1978;
//Do some more stuff with $value
//But $value keeps being > 0
}
return $value;
}
XDebug 代码覆盖报告一次或多次调用此函数时覆盖的所有行。
PHPUnit 在调用一次时报告所覆盖的行。
多次调用它(因为不同的 PHPUnit 测试),PHPUnit 报告 {} 之间的行未被覆盖。
我知道 {} 之间的行由于静态变量 $value 而只执行一次,但恕我直言,执行的行应始终报告为已覆盖,无论它们是否在后续调用中被跳过(通过以下测试)。
我 运行 你的代码并同意,这是 st运行ge 行为,在最后显示不存在的行}
未被覆盖(83% 的覆盖率)。我在 Edge Cases 下的 PHPUnit documentation for Code Coverage 中找到了以下内容:
// Because it is "line based" and not statement base coverage
// one line will always have one coverage status
if (false) this_function_call_shows_up_as_covered();
// 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_covered();
// To avoid this it is necessary that braces are used
if (false) {
this_call_will_never_show_up_as_covered();
}
所以我将最后一个 } 移到了 return 行,它开始报告 100% 的覆盖率。
function itDoesThingsToValue(){
static $value = -1;
if ($value < 0) {
$value = 1978;
//Do some more stuff with $value
//But $value keeps being > 0
}
return $value;}
我还不是很清楚,因为我不了解PHPUnit的来龙去脉,但就是这样...
在第一次单元测试期间调用我的 class 的构造函数时调用该函数。在此测试中,我声明函数被覆盖(使用@covers 注释)。
更进一步,我在数据提供者中再次调用此函数以测试另一个函数。
因为我认为我的函数已经过测试和覆盖(在构造函数测试中),所以应该保存它以便在数据提供程序中使用它。
实际上,这会导致报告的行未被覆盖。
所以我最好的猜测是数据提供者函数 运行 在单元测试之前。
编辑:
添加一些调试代码后,确实确认所有数据提供程序方法在任何测试*方法之前执行。
以下示例产生了我的问题:
public function setUp() {
//Echo the executed testmethod name and 'starting' time into the console.
echo $this->getName(), ' ', date('H:i:s'), chr(10), chr(13);
}
/**
* @covers MyClass::_construct
* @covers MyClass::myMethod
*/
public function testConstructor() {
//Do some stuff
}
public function myDataProvider() {
//Echo the 'starting' time of the data provider method in the console.
echo 'DataProvider started executing at', ' ', date(H:i:s), chr(10), chr(13);
$value = MyClass::myMethod; //This causes the lines not being covered
return [[$value + 1], [$value -1]];
}
/**
* @covers MyClass::AnotherMethod
* @dataprovider myDataProvider
*/
public function testSomethingElse {
//Do some stuff
}
控制台输出:
Testing started at 21:55 ...
DataProvider started executing at 21:55:46
PHPUnit 5.5.5 by Sebastian Bergmann and contributors.
testConstructor 21:55:47
testSomethingElse 21:55:47
我的解决方案是:
private $testClassValue;
/**
* @covers MyClass::_construct
* @covers MyClass::myMethod
*/
public function testConstructor() {
//Do some stuff
$this->$testClassValue = myClass::value;
}
public function myDataProvider() {
$value = $this->$testClassValue;
return [[$value + 1], [$value -1]];
}
/**
* @covers MyClass::AnotherMethod
* @dataprovider myDataProvider
*/
public function testSomethingElse {
//Do some stuff
}
有人可以解释为什么以下功能没有报告为 phpUnit 完全涵盖吗? 或者更好的是,解释如何将其报告为完全覆盖?
function itDoesThingsToValue()
{
static $value = -1;
if ($value < 0) {
$value = 1978;
//Do some more stuff with $value
//But $value keeps being > 0
}
return $value;
}
XDebug 代码覆盖报告一次或多次调用此函数时覆盖的所有行。
PHPUnit 在调用一次时报告所覆盖的行。
多次调用它(因为不同的 PHPUnit 测试),PHPUnit 报告 {} 之间的行未被覆盖。
我知道 {} 之间的行由于静态变量 $value 而只执行一次,但恕我直言,执行的行应始终报告为已覆盖,无论它们是否在后续调用中被跳过(通过以下测试)。
我 运行 你的代码并同意,这是 st运行ge 行为,在最后显示不存在的行}
未被覆盖(83% 的覆盖率)。我在 Edge Cases 下的 PHPUnit documentation for Code Coverage 中找到了以下内容:
// Because it is "line based" and not statement base coverage
// one line will always have one coverage status
if (false) this_function_call_shows_up_as_covered();
// 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_covered();
// To avoid this it is necessary that braces are used
if (false) {
this_call_will_never_show_up_as_covered();
}
所以我将最后一个 } 移到了 return 行,它开始报告 100% 的覆盖率。
function itDoesThingsToValue(){
static $value = -1;
if ($value < 0) {
$value = 1978;
//Do some more stuff with $value
//But $value keeps being > 0
}
return $value;}
我还不是很清楚,因为我不了解PHPUnit的来龙去脉,但就是这样...
在第一次单元测试期间调用我的 class 的构造函数时调用该函数。在此测试中,我声明函数被覆盖(使用@covers 注释)。
更进一步,我在数据提供者中再次调用此函数以测试另一个函数。
因为我认为我的函数已经过测试和覆盖(在构造函数测试中),所以应该保存它以便在数据提供程序中使用它。 实际上,这会导致报告的行未被覆盖。
所以我最好的猜测是数据提供者函数 运行 在单元测试之前。
编辑:
添加一些调试代码后,确实确认所有数据提供程序方法在任何测试*方法之前执行。
以下示例产生了我的问题:
public function setUp() {
//Echo the executed testmethod name and 'starting' time into the console.
echo $this->getName(), ' ', date('H:i:s'), chr(10), chr(13);
}
/**
* @covers MyClass::_construct
* @covers MyClass::myMethod
*/
public function testConstructor() {
//Do some stuff
}
public function myDataProvider() {
//Echo the 'starting' time of the data provider method in the console.
echo 'DataProvider started executing at', ' ', date(H:i:s), chr(10), chr(13);
$value = MyClass::myMethod; //This causes the lines not being covered
return [[$value + 1], [$value -1]];
}
/**
* @covers MyClass::AnotherMethod
* @dataprovider myDataProvider
*/
public function testSomethingElse {
//Do some stuff
}
控制台输出:
Testing started at 21:55 ...
DataProvider started executing at 21:55:46
PHPUnit 5.5.5 by Sebastian Bergmann and contributors.
testConstructor 21:55:47
testSomethingElse 21:55:47
我的解决方案是:
private $testClassValue;
/**
* @covers MyClass::_construct
* @covers MyClass::myMethod
*/
public function testConstructor() {
//Do some stuff
$this->$testClassValue = myClass::value;
}
public function myDataProvider() {
$value = $this->$testClassValue;
return [[$value + 1], [$value -1]];
}
/**
* @covers MyClass::AnotherMethod
* @dataprovider myDataProvider
*/
public function testSomethingElse {
//Do some stuff
}