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

11

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

目前的解决方法是,在测试之间将结果存储在静态属性中。


你尝试过使用 print_r($results); 来查看传递给 testCanDoSomeMoreStuff() 的内容了吗? - uzyn
嗨Uzyn,是的-正在传递null。我还打印了对“my_func”的调用结果,它不是null。 - iainp999
你的代码看起来还不错。也许你想分享一下你的实际代码,因为实际代码中可能存在一些错误。 - uzyn
谢谢您,Uzyn;不幸的是,我不允许发布实际的代码。 - iainp999
3个回答

2
如果你在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($result)进行调试。如果它在那里不是null,请报告此行为

嗨Bjoern。抱歉,我应该补充说这正是我尝试过的,并且它有效。感谢您提供的链接,我将尝试在一个类中重新创建此问题,并将其作为错误报告的一部分提交。 - iainp999

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提交功能请求或拉取请求。


谢谢David,这非常有用。我昨天已经在Github上报告了问题,并附上了示例代码,所以我想现在就把它留给他们处理。 - iainp999

2
我也曾期望所描述的问题能够解决,但经过一番研究后,我发现这并不是一个错误,而是一种预期但未记录下来的行为。依赖测试不知道提供程序返回的数据集,这就是为什么测试参数为空的原因。
来源:https://github.com/sebastianbergmann/phpunit/issues/183#issuecomment-816066 @dataProvider 注释在测试执行之前计算。基本上,预测试阶段为提供程序提供的每组参数创建一个测试方法。 @depends 依赖于数据驱动测试的原型,因此可以说 @depends 在不存在(未执行的测试)上。
另一种思考方式是,如果提供程序提供了多个参数集,则 PHPUnit 将创建相同数量的 testDataProvider 方法,但是 testDataReceiver 方法将没有那么多,因为在预测试阶段该测试方法上没有 @dataProvider 方法。
但是,您始终可以同时使用 @depend 和 @dataProvider 来实现大致相同的行为。只需小心获取参数顺序即可。
基本上,当数据集有多行时,应该使用数据提供程序。但是,您始终可以同时使用 @depend 和 @dataProvider 来实现大致相同的行为。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接