【问题标题】:Can I use @depends to depend on a test using an @dataProvider?我可以使用@depends 来依赖使用@dataProvider 的测试吗?
【发布时间】:2012-05-29 06:26:30
【问题描述】:

我有一个测试类,其中一个测试通过@dataProvider 运行多次,另一个测试通过@depends 在第一种方法上运行。然而,当我打电话给var_dump 关于应该通过第二次测试的内容时,它给了我一个可靠的NULL,这是我没想到的。

换句话说:这应该怎么做:

<?php 
class DevicesTest extends PHPUnit_Framework_TestCase
{
    /**
     * @dataProvider registerDataProvider
     */
    public function testRegister($device, $supposedResult)
    {
        //do a bunch of tests
        return array($device, $supposedResult);
    }

    public function registerDataProvider()
    {
        return array(array("foo", "foo"));
    }

    /**
     * @depends testRegister
     */
    public function testSaveDevicePreferences($deviceArr)
    {
        $this->assertNotEmpty($deviceArr);
    }
}
?>

【问题讨论】:

    标签: php unit-testing phpunit


    【解决方案1】:

    在 PHPUnit 的当前版本(截至今天的 5.4)中,这是可能的。

    根据documentation

    当一个测试从@dataProvider 方法和它@depends 的一个或多个测试接收输入时,来自数据提供者的参数将在来自依赖测试的参数之前。依赖测试的参数对于每个数据集都是相同的。

    实际上是这样的:

    <?php
    
    class DataProviderAndDependsCombinationTest extends AbstractUnittest{
    
        public function dataProviderForSomething()
        {
            return array(
                array(
                    'someProvidedValue',
                    'someOtherProvidedValue'
                )
            );
        }
    
        public function testToDependOn()
        {
            $this->assertTrue(true);
            return 'someDependedValue';
        }
    
         /**
         * @dataProvider dataProviderForSomething
         * @depends testToDependOn
         */
        public function testSomething($someProvidedValue, $someOtherProvidedValue, $someDependedValue)
        {
            $this->assertSame('someProvidedValue', $someProvidedValue);
            $this->assertSame('someOtherProvidedValue', $someOtherProvidedValue);
            $this->assertSame('someDependedValue', $someDependedValue);
        }
    }
    

    【讨论】:

    • 没错。对于当前状态,这应该被接受。
    • 虽然不是问题所在。 OP 在依赖的测试上有@dataProvider,而不是依赖于另一个的测试(就像你在这里一样)。
    • 很好的答案,这绝对应该是公认的答案!
    【解决方案2】:

    通常@dataProvider 用于当您想要多次运行测试时使用不同的数据集。它的存在是为了避免您在测试中编写循环代码,并允许不同的数据集分别通过或失败。

    正如我在 cmets 中所说,我相信 PHPUnit 将使用 @depends @dataProvider,从您的示例中我猜第二个会胜出。另一种可能性是数据提供者的测试不能用作依赖项,因为 PHPUnit 不知道要选择哪个测试加数据集。

    由于registerDataProvider 返回单个数据集,您可以轻松地从测试本身调用它。这将允许@depends 在没有@dataProvider 的情况下在第二个测试中工作。假设testRegister 需要修改$device 和/或$supposedResult,这应该可以工作:

    class DevicesTest extends PHPUnit_Framework_TestCase {
        public function testRegister() {
            list($device, $supposedResult) = $this->registerDataProvider();
            //do a bunch of tests
            //register a device in the DB
            return array($device, $supposedResult);
        }
    
        public function registerDataProvider() {
            return array("foo", "foo");
        }
    
        /**
         * @depends testRegister
         */
        public function testSaveDevicePreferences($data) {
            list($device, $supposedResult) = $data;
            // do stuff dependent on testRegister()
            $this->assertEquals($device, $supposedResult);
        }
    }
    

    如果第一次测试不需要修改这些变量,您可以简单地从两个测试中调用registerDataProvider。请注意,PHPUnit 不会像数据提供者机制那样将返回的数组与依赖测试分离成依赖测试的参数。这是因为它不知道返回的数组是多个参数还是单个参数。

    【讨论】:

    • 请参阅github.com/sebastianbergmann/phpunit/issues/… 了解有关此行为的说明
    • @dataProvider 的数据排在第一位,@depends 的数据排在第一位。这就是它对我的工作方式。
    • 这样操作会丢失一些不错的错误报告。似乎适合 PHPUnit 1)为每个提供的数据迭代调用所有依赖测试,或 2)将最后一次迭代的返回值转发给依赖测试。
    【解决方案3】:

    我发现不,这是不可能的。但是,通过稍微调整测试类,我已经获得了基本相同的结果,但是,依赖关系似乎丢失了,如果第一个测试失败,第二个会愉快地运行:

    <?php 
    class DevicesTest extends PHPUnit_Framework_TestCase
    {
        /**
         * @dataProvider registerDataProvider
         */
        public function testRegister($device, $supposedResult)
        {
            //do a bunch of tests
            //register a device in the DB
            return array($device, $supposedResult);
        }
    
        public function registerDataProvider()
        {
            return array(array("foo", "foo"));
        }
    
        /**
         * @depends testRegister
         * @dataProvider registerDataProvider
         */
        public function testSaveDevicePreferences($device, $supposedResult)
        {
            // do stuff dependent on testRegister()
            $this->assertEquals($device, $supposedResult);
        }
    }
    ?>
    

    【讨论】:

    • 我很好奇当数据提供者方法返回一个包含多个参数数组的数组时它的行为如何。每个参数数组都应该调用一次测试方法,但测试依赖项设计为依赖于单个测试方法调用。
    • 它的行为有点正确,但是,正如我编辑的那样,如果第一个测试失败,第二个测试不会被跳过。此外,第二个测试取决于数据库中存在的一些东西,这些东西是由第一个测试放在那里的。他们在那里的事实意味着第一个测试确实在第二个测试之前运行。
    • 测试按照它们声明的顺序运行。 PHPUnit 不会根据依赖关系图对它们重新排序。由于第二个测试使用相同的数据提供者,它从该方法而不是它所依赖的测试接收数据。我敢打赌,PHPUnit 在@depends 之前查找@dataProvider,因此您可以删除依赖项而没有效果。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-11
    • 1970-01-01
    • 1970-01-01
    • 2013-10-25
    • 1970-01-01
    相关资源
    最近更新 更多