我有一个测试方法,它依赖于另一个方法,该方法本身使用PHPUnit中的数据提供程序:
/**
* @dataProvider getFields
*/
public function testCanDoSomeStuff($parm1, $parm2) {
$result = my_func($parm1, $parm2);
$this->assertNotNull($result);
return $result;
}
/**
* @depends testCanDoSomeStuff
*/
public function testCanDoSomeMoreStuff($result) {
$this->assertNotNull($result);
}
我还有一个getFields()
数据提供程序函数,这里不需要显示。
依赖于数据提供程序的第一个测试通过-$result
不是null。
我希望测试结果将作为$result
参数传递给相关测试。但是,testCanDoSomeMoreStuff
函数接收到NULL
参数,测试失败。
更新
这个简单的测试用例说明了问题:
class MyTest extends PHPUnit_Framework_TestCase {
/**
* @dataProvider myFunc
*/
public function testCanDoSomeStuff($value) {
$this->assertNotNull($value);
return $value;
}
/**
* @depends testCanDoSomeStuff
*/
public function testCanDoSomeMoreStuff($value) {
$this->assertNotNull($value);
}
/**
* Data provider function
*/
public function myFunc() {
$values = array('22');
return array($values);
}
}
作为目前的解决方法,我已将结果存储在测试之间的静态属性中。
问题是几个因素造成的:
- 每个测试结果都存储在一个数组中,使用测试的名称作为关键字
- 接收数据的测试的名称为
<name> with data set #<x>
@depends
注释不接受多个单词
有一个巧妙的解决方法:重写TestCase::getDataSetAsString
以返回注释将接受的名称。这有点问题,因为所需的TestCase
字段是私有的,但使用PHP 5.3.2+可以绕过这一点。
重要信息:不幸的是,您不能为的每个数据行运行依赖测试,只能运行一个特定的行。如果您的数据提供程序只返回一行数据,则这不是问题。
这是带有示例测试的代码。请注意,您不必为数据行命名。如果关闭'foo'
键,请将@depends
更改为testOne-0
。
class DependencyTest extends PHPUnit_Framework_TestCase
{
/**
* @dataProvider data
*/
public function testOne($x, $y) {
return $x + $y;
}
public function data() {
return array(
'foo' => array(1, 2),
);
}
/**
* @depends testOne-foo
*/
public function testTwo($z) {
self::assertEquals(3, $z);
}
protected function getDataSetAsString($includeData = false) {
if (!$includeData && $this->getPrivateField('data')) {
return '-' . $this->getPrivateField('dataName');
}
return parent::getDataSetAsString($includeData);
}
private function getPrivateField($name) {
$reflector = new ReflectionProperty('PHPUnit_Framework_TestCase', $name);
$reflector->setAccessible(true);
return $reflector->getValue($this);
}
}
显然,这不是一个长期的解决方案。对于接收数据的方法的每个测试结果,最好可以让依赖测试运行一次。您可以向PHPUnit提交功能请求或拉取请求。
如果testCanDoSomeStuff()
中的$result
真的不是null
,那么这应该有效。
要将其拆开,首先尝试在没有数据提供商的情况下简化它,类似于以下内容:
class StackTest extends PHPUnit_Framework_TestCase {
public function testCanDoSomeStuff() {
$result = true;
$this->assertTrue($result);
return $result;
}
/**
* @depends testCanDoSomeStuff
*/
public function testCanDoSomeMoreStuff($result) {
$this->assertNotNull($result);
}
}
测试这应该会导致类似。。。
~>phpunit test.php
PHPUnit 3.6.11 by Sebastian Bergmann.
..
Time: 1 second, Memory: 3.25Mb
OK (2 tests, 2 assertions)
现在添加数据提供程序,用函数替换我的简单变量,然后再次测试它。
如果此结果不同,则在测试用例testCanDoSomeStuff()
中返回变量$result
之前,先将其var_dump
。如果不是null
,则对行为进行bug处理。
我也希望所描述的问题能起作用,经过一些研究,我发现这不是一个bug,而是一种预期的、没有记录的行为。依赖测试不知道提供程序返回的数据集,这就是测试参数为null的原因。
来源:https://github.com/sebastianbergmann/phpunit/issues/183#issuecomment-816066
@dataProvider注释在测试执行之前进行计算。基本上,预测试阶段为数据提供者提供的每一组参数创建一个测试方法。@dependents依赖于数据驱动测试的原型,因此在某种程度上@dependent依赖于不存在的(未执行的测试)。
另一种想法是,如果提供者提供了一组以上的参数。PHPUnit会生成那么多testDataProvider方法,但不会有那么多testDataReceiver方法,因为在测试前阶段,该测试方法上没有@dataProvider方法。
但是,您可以在相同的测试方法上使用@dependents和@dataProvider。尽管在这种情况下可能没有第一个参数,但要注意正确的参数顺序。
基本上,当数据集有多行时,应该使用数据提供程序。但是,您可以始终同时使用@depend
和@dataProvider
来实现大致相同的行为。