将依赖项与数据提供程序相结合

时间:2012-07-24 11:09:03

标签: php phpunit

我有一个测试方法依赖于另一个本身在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);
    }
}

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

3 个答案:

答案 0 :(得分:2)

如果$result中的testCanDoSomeStuff()确实不是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()之前。如果不是nullbug the behaviour

答案 1 :(得分: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提交功能请求或拉取请求。

答案 2 :(得分:2)

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

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

  

在测试执行之前计算@dataProvider注释。基本上,预测试阶段为数据提供者提供的每组参数创建测试方法。 @depends取决于基本上是数据驱动测试的原型,所以在某种程度上@depends是不存在的(未执行的测试)。

     

另一种思考方式是,如果提供者提供了多组参数。 PHPUnit会生成那么多的testDataProvider方法,但是没有那么多的testDataReceiver方法,因为在测试阶段没有针对预测试阶段的@dataProvider方法。

     

但是,您可以在同一测试方法上使用@depends和@dataProvider。请注意使参数顺序正确,尽管在这种情况下可能没有第一个参数。

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