[准备 PHPUnit12] [信息] 未找到测试 ←此 [数据提供程序]

[准备 PHPUnit12] [信息] 未找到测试 ←此 [数据提供程序]

介绍

我是系统开发部的榎木。
这次,我将介绍如何解决使用数据提供程序运行测试时出现的“INFO No tests found.”错误。
解释比较长,如果您只想了解答案,结论部分请直接跳到

主线剧情

开始

*请忽略测试内容在本篇文章中并不重要的事实,所以不必担心它是否算得上一个完整的测试。

我:“我们来写个测试……这次的测试内容,数据提供器就够用了!”我:“哼。”
<?php namespace Tests\Unit; use PHPUnit\Framework\Attributes\DataProvider; use Tests\TestCase; class DataProviderTest extends TestCase { /** * @return array */ public function provideParam(): array { return[ 'params' => ['data', 'true'], ]; } /** * @dataProvider provideParam */ public function test_DataProviderTest($data, $expected) $this->assertTrue(true); } }
root:/var/www/html/src# php artisan test tests/Unit/DataProviderTest.php 警告:在 Tests\Unit\DataProviderTest::test_DataProviderTest() 方法的文档注释中发现了元数据。文档注释中的元数据已被弃用,PHPUnit 12 将不再支持此功能。请更新您的测试代码以使用属性。 信息:未找到测试。.

我:“啊?”
我:“哇,原来从 PHPUnit12 开始,是用属性而不是文档来指定!我明白了!”
*这个属性是这样的 → #[]

#[DataProvider('provideParam')] public function test_DataProviderTest($data, $expected) { $this->assertTrue(true); }

我:“好的。”
我:“开始吧。”

root:/var/www/html/src# php artisan test tests/Unit/DataProviderTest.php INFO 未找到测试。.

我:“啊?”

主题

我仿佛都能听到有人说:“这出闹剧没完没了。”总之,重点是它显示“找不到测试”。你们遇到这种情况会怎么做?我想你们会尝试类似 `php artisan optimize:clear` 或 `composer dump-autoload` 这样的命令,或者检查命名空间和文件名。(请务必这样做。)当然,我一开始也觉得“哦,又是老毛病了”。但我写这篇文章,自然意味着问题并没有解决。我想让你们记住的是,它显示的是 INFO 信息。通常情况下,如果你指定并运行一个不存在的测试,它会显示成这样:
root:/var/www/html/src# php artisan test tests/Unit/NoneTest.php PHPUnit 11.2.2 by Sebastian Bergmann and contributors. 未找到测试文件“tests/Unit/NoneTest.php”。

这意味着该测试必然存在,但却找不到。接下来,我创建了一个合适的测试来验证这个理论是否正确。
<?php namespace Tests\Unit; use PHPUnit\Framework\Attributes\DataProvider; use Tests\TestCase; class DataProviderTest extends TestCase { /** * @return array */ public function provideParam(): array { return[ 'params' => ['data', 'true'], ]; } public function test_Appropriate test() { $this->assertTrue(true); } #[DataProvider('provideParam')] public function test_Data provider test($data, $expected) { $this->assertTrue(true); } }
root:/var/www/html/src# php artisan test tests/Unit/DataProviderTest.php 失败 Tests\Unit\DataProviderTest ⨯ 数据提供程序测试 ✓ 测试合适 0.06秒 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 失败 Tests\Unit\DataProviderTest > 数据提供程序测试 为 Tests\Unit\DataProviderTest::test_dataprovider 测试指定的数据提供程序无效 数据提供程序方法 Tests\Unit\DataProviderTest::provideParam() 不是静态的 测试:1 个失败,1 个通过(1 个断言) 持续时间:0.10秒

结果比预期要好。不仅文件被识别,测试也成功了,
甚至还给出了准确的错误信息。
看来他们希望 `dataProvider` 方法是静态的,
这样它就会变成一个自动跟踪错误的程序。

<?php namespace Tests\Unit; use PHPUnit\Framework\Attributes\DataProvider; use Tests\TestCase; class DataProviderTest extends TestCase { /** * @return array */ public static function provideParam(): array { return[ 'params' => ['data', 'true'], ]; } #[DataProvider('provideParam')] public function test_DataProviderTest($data, $expected) { $this->assertTrue(true); } }

root:/var/www/html/src# php artisan test tests/Unit/DataProviderTest.php PASS Tests\Unit\DataProviderTest ✓ 使用数据集“params”测试数据提供程序 0.06秒 测试:1 个通过(1 个断言) 持续时间:0.09秒

成功了!
看来如果我们把用作数据提供程序的方法设为静态方法,它就能按预期工作了。
问题暂时解决了,但我还想探究一下“INFO No tests found”这条信息背后的原因。

调查原因

根据我们目前掌握的信息,我们可以做出这样的假设:“用作数据提供程序的方法必须是静态的”。
第一次执行结果对此很有帮助。

root:/var/www/html/src# php artisan test tests/Unit/DataProviderTest.php 警告:在 Tests\Unit\DataProviderTest::test_DataProviderTest() 方法的文档注释中发现了元数据。文档注释中的元数据已被弃用,PHPUnit 12 将不再支持此功能。请更新您的测试代码以使用属性。 信息:未找到测试。. 

如您所见,在文档注释中使用 `dataProvider` 仅显示警告,因为它仍处于“已弃用”状态。
这表明,如果 `dataProvider` 方法是静态的,则应该可以正确执行。

<?php namespace Tests\Unit; use PHPUnit\Framework\Attributes\DataProvider; use Tests\TestCase; class DataProviderTest extends TestCase { /** * @return array */ public static function provideParam(): array { return[ 'params' => ['data', 'true'], ]; } /** * @dataProvider provideParam */ public function test_DataProviderTest($data, $expected) { $this->assertTrue(true); } }

 

root:/var/www/html/src# php artisan test tests/Unit/DataProviderTest.php 警告:在方法 Tests\Unit\DataProviderTest::test_DataProviderTest() 的文档注释中发现了元数据。文档注释中的元数据已被弃用,PHPUnit 12 将不再支持。请更新您的测试代码以使用属性代替。通过 Tests\Unit\DataProviderTest ✓ 使用数据集“params”的 DataProvider 测试 0.09 秒 测试:1 个通过(1 个断言) 持续时间:0.14 秒

测试执行成功,正如我所假设的那样。
但是,为什么需要静态数据呢?凭我的记忆和查看源代码,之前并不需要静态数据。
所以我进行了调查。
(参考:https

公共的
且静态的。
它必须返回一个可迭代的值,可以是数组,也可以是实现了 Traversable 接口的对象。
翻译
数据提供程序方法必须是公共的且静态的。它们必须返回一个可迭代的值(数组或实现了 Traversable 接口的对象)。

情况似乎确实如此。让我们密切关注这些变化。
此外,还有以下声明:


一个测试依赖于另一个使用数据提供程序的测试时,依赖测试只有在被依赖的测试至少在一个数据集上成功通过后才会执行。
使用数据提供程序的测试结果不能注入到依赖测试中。
翻译
测试依赖于使用数据提供程序的测试,则依赖测试只有在依赖测试至少在一个数据集上成功后才会运行。使用数据提供程序的测试结果不会注入到依赖测试中。

看来这就是我添加合适的测试时出错的原因。
仔细想想,这的确是一个令人无语的真理。
如果测试之前的代码部分存在缺陷,而现有的测试都假设存在这个缺陷,那么出现“未找到测试”的错误就完全合情合理了。

结论

dataProvider 的目标方法必须是静态方法。

附注

为什么需要静态的?
(我害怕有人会说:“你凭什么只发表意见?作为工程师,你应该提供源代码。”)我怀疑是为了“确保测试数据与其他测试的独立性”。可复现性和不影响其他测试在测试中至关重要,而静态数据可以确保提供不依赖于实例状态的纯净数据。我

查阅了各种官方资料,找到了关于“必须静态化!”的更新信息。然而,我找不到任何关于他们为何强制要求静态化的原因……(如果有人知道,请务必告诉我。)
如果您觉得这篇文章对您有帮助,请点个“赞”!
12
加载中...
12票,平均分:1.00/112
1,547
X Facebook Hatena书签 口袋

这篇文章的作者

关于作者

榎木

我什么游戏都玩,包括第一人称射击游戏、角色扮演游戏、大型多人在线游戏和建造类游戏。