2012-07-24 123 views
10

结合依赖我有依赖于本身使用的数据提供者在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不为空。

我预计测试结果将作为$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); 
    } 
} 

作为一种解决方法,现在,我已经存储的结果在测试之间的静态属性。

+0

您是否尝试过'print_r($ results);'查看传递给'testCanDoSomeMoreStuff()'的东西? – uzyn 2012-07-24 11:16:55

+0

嗨Uzyn,是的 - null正在通过。我还将调用的结果打印到“my_func”,该结果不为null。 – iainp999 2012-07-24 11:19:09

+0

你的代码对我来说看起来不错。也许你可能想分享你的实际代码,但实际中可能会有一些错误。 – uzyn 2012-07-24 11:20:04

回答

2

问题是几个因素的结果:

  • 每个测试结果被存储在使用测试的名字作为密钥的阵列。
  • 接收数据的测试的名称是<name> with data set #<x>
  • @depends注释不接受多个单词。

有一个hacky的解决方法:覆盖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提交功能请求或拉取请求。

+0

谢谢David,这非常有用。我昨天连同示例代码一起在github上报告了这个问题,所以我想我现在就把它留给他们。 – iainp999 2012-07-25 09:26:54

2

如果您在$resulttestCanDoSomeStuff()真的不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) 

现在添加数据提供程序,用您的函数替换我的简单变量,然后再次测试它。

如果此结果不同,请将var_dump变量$result返回给测试用例testCanDoSomeStuff()。如果不是null那里,bug the behaviour

+0

嗨Bjoern。对不起,我应该补充说,这正是我也试过的,并且它工作。感谢您的链接,我会尝试在我可以作为错误报告一部分提交的类中重新创建问题。 – iainp999 2012-07-24 12:57:02

2

我也希望所描述的问题能起作用,经过一番研究后,我发现这不是一个错误,而是一个预期的,没有记录的行为。依赖测试不知道提供者返回的数据集,这就是测试参数为null的原因。

来源:https://github.com/sebastianbergmann/phpunit/issues/183#issuecomment-816066

的@dataProvider注释测试执行前得到计算。基本上,预测试阶段为数据提供者提供的每组参数创建一个测试方法。 @depends依赖于本质上是数据驱动测试的原型,所以@depends在一个不存在的(未执行的测试)上。

另一种想法是,如果提供者提供了多个参数集。 PHPUnit会创建许多testDataProvider方法,但不会有那么多的testDataReceiver方法,因为在测试阶段没有针对该测试方法的@dataProvider方法。

然而,您可以在相同的测试方法上使用@depends和@dataProvider。只要小心获取正确的参数顺序,虽然在这种情况下可能没有第一个参数。

基本上,当数据集有多行时,应该使用数据提供者。但是,您始终可以同时使用@depend@dataProvider以实现大致相同的行为。