Phpunit: 数据提供者在 setupBeforeClass 之前执行

创建于 2013-02-21  ·  21评论  ·  资料来源: sebastianbergmann/phpunit

数据提供者在静态setupBeforeClass执行之前被调用。 如果认为它应该是相反的。

用例:

  • 我们有一个适配器列表。 某些适配器仅在某些环境(即 Linux 与 Win)上受支持,
  • 我想初始化一次支持的适配器列表,然后通过数据提供程序将其传递给所有测试,
  • 我能想象的最干净的方法是在setupBeforeClass初始化一个静态属性,并让提供者返回该属性

问题是在调用提供程序时未初始化该属性。

找到的版本:3.7.14

最有用的评论

@epdenouden JIT? 你是在用 JIT 测试 PHP,还是有什么我不知道的? 对不起,我有点困惑; 你说的是 PHP7.x 和 PHP8.x 还是 PHPUnit7.x 和 PHPUnit8.x?!

@MAChitgarha我理解你的困惑,因为 PHP8 正在获得一个及时的 _compiler_。 我使用的术语是基于相同想法的新数据提供程序实现:即时 _loader_ 又名延迟加载。 仅在需要时初始化您需要的内容。

这将适用于即将推出的 PHP 版本 8 JIT,因为它不使用 PHP 语言本身的任何棘手功能。 我所有的工作都深入 PHPUnit,重做配置解析、测试加载和运行等。

如果看起来我什么都没做,那我就做对了。 除了降低的 GCP 或 AWS 发票。 💸

所有21条评论

如果您认为数据提供者不需要是静态的,甚至不需要在同一个测试类中,我不确定强制执行某些命令以便静态资源可以在setupBeforeClass初始化是否真的有意义。

为什么不只是延迟初始化适配器? 那么顺序根本不重要。

如果不运行数据提供者,我们不知道测试方法运行了多少测试。 在一个完美的世界中,我们会打破 B/C 并要求数据提供者是实现扩展Countable接口的对象。 这样我们就可以将这些关注点分开并有一个更干净的情况。

@whatthejeff这是什么,我们最终做。 然而,在构造函数中初始化可能会更清晰一些,因为从提供程序返回时参数必须包装在数组中。

@sebastianbergmann好的,我明白为什么他们之前被称为,在文档中提到它怎么样? (如果你没问题,我可以打开一个 PR 来改变)。 我什至不确定拥有对象会有多大帮助:如果您看看我的前任,就会发现从一个提供者到另一个提供者之间存在依赖性。

感谢您的回复,关闭issue。

@vicb ,我很乐意

我可能有点晚了,但是当我有需要初始化的依赖项时,我碰巧做的是放弃@dataProvider注释并使用yield代替。

@srosato我傻了(我没用过 yield)。 你能举一个简单的例子来说明如何做到这一点吗? 如果此处的示例不合适,请访问 https://gist.github.com

如果您的@dataProvider需要设置代码并且它们不是特别大,您可以在测试中将它们指定为字符串和eval它们。 例如:

public function myProvider() {
    return [
        'new Klass("param 1", "param 2")',
        'new Klass("param 1", "param 2")',
    ];
}

/**
 * <strong i="8">@dataProvider</strong> myProvider
 */
public testMyFunction($instance_str) {
    $klass = eval("return {$instance_str};");
    # continue testing $klass ...
}

我的两分钱:

而不是依赖于静态属性(我们知道这是不可能的)的数据提供者,我将所需的数据/对象设置为setUp()方法中测试类的类成员。
tearDown()我将它/它们设置为空,或者当有复杂的对象时,我为它实现了一个clear()方法。

只要没有太多测试类范围的依赖项,我就对这种方法感到满意。
但是当有超过一两个这样的依赖项时,您可能需要过度考虑您的整体设计。

具体来说,我使用一个 DB 连接作为静态属性,它在setUpBeforeClass()设置并设置$queryBuilder ,它获取连接注入,作为setUp()的类成员(而不是在数据提供程序中返回它)。

一个解决方案是定义一个新的私有方法,并根据需要定义尽可能多的变量,如其中的static变量。 然后,检查是否设置了其中之一,如果没有,则设置所有这些并返回(或放弃)它们。 这样,_变量将只声明一次_,即使您有十个提供者或其他什么。 此外,您可以在setUpBeforeClass()setUp()

在一个例子中看到它:

private static function getData()
{
    static $data, $anotherData;

    if (!isset($data)) {
        $data = new TestClass();
        $anotherData = [];
    }

    return [
        $data,
        // Or: clone $data
        $anotherData,
    ];
}

public static function setUpBeforeClass()
{
    list(self::$sampleJson, self::$sampleData) = self::getData(); 
}

public function sampleProvider()
{
    $data = self::getData();

    return [
        $data
    ];
}

@MAChitgarha感谢您昨天的评论,我发现了这张票。 :)

我正在重构#3736 中的数据提供者逻辑,这将解决一些常见问题:

  • 随着所有数据提供者都被加载,在运行开始时不再有这种巨大的活动高峰
  • 数据提供者可以在灯具setUpBeforeClasssetUp
  • 非静态数据提供者成为可能
  • 发电机会更有效率

@epdenouden 很高兴听到这个消息! ;) 您列表中的第二个项目是一个很好的项目。 等待那个。

非静态数据提供者成为可能

目前不可以吗? 我总是在我的测试中使用非静态数据提供程序而不是静态数据提供程序,并且它们按预期工作没有问题(使用 PHPUnit 7.5.6)。 我错了吗?

目前不可以吗? 我总是在我的测试中使用非静态数据提供程序而不是静态数据提供程序,并且它们按预期工作没有问题(使用 PHPUnit 7.5.6)。 我错了吗?

不,你是对的! 我的措辞不够准确,谢谢你提出这个问题。 在它当前读取的数据提供程序处理代码的深处:

private static function getDataFromDataProviderAnnotation($allTheParameters): ?iterable
    // code for locating the data provider
    // [...]
                if ($dataProviderMethod->isStatic()) {
                    $object = null;
                } else {
                    $object = $dataProviderClass->newInstance();
                }

    // code for preparing returned data rows
    // [...]
}

所以这是肮脏的小秘密:

  • 您可以使用非静态数据提供程序和
  • 他们将在实际instanceof上被调用,但是......
  • 它_不是用于夹具和测试的相同实例_

你给了我一些关于数据提供者重构的思考和验证! 我需要添加额外的测试以确保对象实例是预期的,而不仅仅是相同的类型或克隆。 ☕️ 和 🍰 当你在阿姆斯特丹的时候。

@MAChitgarha实例确实不同: https :

image

@epdenouden但我没有失败! 在 PHPUnit 7.5.13 中,断言不会产生任何错误。 你怎么得到这个错误? 向后不兼容,你的意思是?

这是在我正在处理的基于 8.2 的延迟加载数据提供程序分支中。 我接下来会检查 7.5.x,感谢您的提醒。

如果这行得通,我将不得不回到其他一些明确要求实现非静态提供程序方法的旧问题,并再次查看确切的用例。

无论如何:您的评论已经激发了一个非常有用的测试:)

@MAChitgarha是的,这将是一个 BC 中断

@epdenouden我会等的。 出于某些原因,在我的项目中,我使用的是 PHPUnit 7.5.13; 但我很快就会将其更新到 8.2.*。 好消息是,如果可以修复 BC-break。 我不知道 PHPUnit 本身的结构,所以我不知道你改变了什么,但我想可以修复它。 然而,这一切都取决于你! :)

好消息是,如果可以修复 BC-break。 我不知道 PHPUnit 本身的结构,所以我不知道你改变了什么,但我想可以修复它。 然而,这一切都取决于你! :)

@sebastianbergmann不允许在没有充分理由的情况下引入向后兼容性中断,因此它将在进入下一个版本之前修复。 PHPUnit 是一种用于保护 PHP 社区而非我个人游乐场中软件质量的工具。

所以是的,请告诉我们您希望作为测试的最终用户/开发人员看到什么。 请记住,像这样的项目没有大量的志愿者开发人员。

有趣的事实:上面的测试确实适用于 7.x 和 8.x 版本,但在 JIT 原型上失败。

我正在处理的代码仍然更像原始代码流。 所以这可能是一个错误的结果,一些我仍然需要进一步重构的仍然逻辑,一些关于 PHP 中的对象和反射的低级别的东西我需要查找或者可能只是我的一些天真的测试。 🔬

@epdenouden JIT? 你是在用 JIT 测试 PHP,还是有什么我不知道的? 对不起,我有点困惑; 你说的是 PHP7.x 和 PHP8.x 还是 PHPUnit7.x 和 PHPUnit8.x?!

@epdenouden JIT? 你是在用 JIT 测试 PHP,还是有什么我不知道的? 对不起,我有点困惑; 你说的是 PHP7.x 和 PHP8.x 还是 PHPUnit7.x 和 PHPUnit8.x?!

@MAChitgarha我理解你的困惑,因为 PHP8 正在获得一个及时的 _compiler_。 我使用的术语是基于相同想法的新数据提供程序实现:即时 _loader_ 又名延迟加载。 仅在需要时初始化您需要的内容。

这将适用于即将推出的 PHP 版本 8 JIT,因为它不使用 PHP 语言本身的任何棘手功能。 我所有的工作都深入 PHPUnit,重做配置解析、测试加载和运行等。

如果看起来我什么都没做,那我就做对了。 除了降低的 GCP 或 AWS 发票。 💸

此页面是否有帮助?
0 / 5 - 0 等级