PHP函数在多次调用时未报告为完全由PHPUnit覆盖

时间:2016-10-01 19:28:10

标签: php phpunit code-coverage

有人可以解释为什么下面的函数没有被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而执行一次,但imho执行的行应始终报告为覆盖,无论它们是否在以下调用中跳过(通过以下测试)。

2 个答案:

答案 0 :(得分:1)

我运行了你的代码并同意,这是一种奇怪的行为,在最后}显示一条不存在的行,因为没有覆盖(83%的覆盖率)。我在边缘情况下的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();
}

所以我将最后一个移到了返回线,它开始报告100%的覆盖率。

function itDoesThingsToValue(){
static $value = -1;
if ($value < 0) {
    $value = 1978;
    //Do some more stuff with $value
    //But $value keeps being > 0
}
return $value;}

答案 1 :(得分:0)

我还不完全清楚,因为我不知道PHPUnit的来龙去脉,但情况就是这样......

在第一次单元测试期间调用我的类的构造函数时调用该函数。在这个测试中,我声明该函数被覆盖(使用@covers注释)。

在某个地方,我在数据提供者中再次调用此函数来测试另一个函数。

因为我认为我的函数已经过测试和覆盖(在构造函数测试中),所以应该保存它以在dataprovider中使用它。 实际上,这会导致报告的行未被覆盖。

所以我最好的猜测是在单元测试之前运行dataprovider函数。

修改

添加一些调试代码后,确实确认所有数据提供程序方法在任何测试*方法之前执行。

以下示例产生了我的问题:

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
}