【PHPUnit12に備えろ】[ INFO ] No tests found ←これ【dataProvider】
目次 [非表示]
【PHPUnit12に備えろ】[ INFO ] No tests found ←これ【dataProvider】
はじめに
システム開発部の榎木です。
今回は dataProvider を使ったらテスト実行時に INFO No tests found.と出てきた際の解決法について記述します。
茶番が長いので、答えだけ知りたい人は結論だけ見てください。
本編
ことのはじまり
※ この記事において、テスト内容は微塵も重要ではないので、テストの体を成していないことは気にしないでください。
ぼく「テスト書くか~、、、このテスト内容なら dataProvider でええな!」
ぼく「フンッ」
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <? 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_データプロバイダーのテスト($data, $expected) $this->assertTrue(true); } } |
1 2 3 4 5 6 7 | root:/var/www/html/src# php artisan test tests/Unit/DataProviderTest.php WARN Metadata found in doc-comment for method Tests\Unit\DataProviderTest::test_データプロバイダーのテスト(). Metadata in doc-comments is deprecated and will no longer be supported in PHPUnit 12. Update your test code to use attributes instead. INFO No tests found. |
ぼく「ん?」
ぼく「はえ~ PHPUnit12 からは Doc じゃなくて属性で指定するんやな!わかったで!」
※属性はこれ→ #[]
1 2 3 4 5 | #[DataProvider('provideParam')] public function test_データプロバイダーのテスト($data, $expected) { $this->assertTrue(true); } |
ぼく「ほいよ」
ぼく「実行っと」
1 2 3 | root:/var/www/html/src# php artisan test tests/Unit/DataProviderTest.php INFO No tests found. |
ぼく「ゑ?」
本題
茶番がなげーよという声が聞こえてきそうですね。
さておきとにかく、ここで重要なのは「テストが見つからない」と言われていることです。
こういうとき皆さんはどうされるでしょうか。
とりあえず php artisan optimize:clear とか、composer dump-autoload とか、
namespaceやファイル名の見直しとか、そういうことをされるんじゃないでしょうか。(してください。)
私も当然のごとく「あ~いつものアレね」くらいの感覚でした。
しかしこの記事を書くということはこれまた当然のことながら直らなかったわけです。
ここで思い出してほしいのが、あくまで INFO として出てきたということです。
通常、存在しないテストを指定・実行すると下記のようになります。
1 2 3 4 | root:/var/www/html/src# php artisan test tests/Unit/NoneTest.php PHPUnit 11.2.2 by Sebastian Bergmann and contributors. Test file "tests/Unit/NoneTest.php" not found |
ということはテストはきちんと存在しているはずなのに見つからないのです。
次に私は、適当なテストを作ってこの説が正しいのかを確認してみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <? 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_適当なテスト() { $this->assertTrue(true); } #[DataProvider('provideParam')] public function test_データプロバイダーのテスト($data, $expected) { $this->assertTrue(true); } } |
1 2 3 4 5 6 7 8 9 10 11 | root:/var/www/html/src# php artisan test tests/Unit/DataProviderTest.php FAIL Tests\Unit\DataProviderTest ⨯ データプロバイダーのテスト ✓ 適当なテスト 0.06s ───────────────────────────────────────────────────────────────────────────────────────────────────────────── FAILED Tests\Unit\DataProviderTest > データプロバイダーのテスト The data provider specified for Tests\Unit\DataProviderTest::test_データプロバイダーのテスト is invalid Data Provider method Tests\Unit\DataProviderTest::provideParam() is not static Tests: 1 failed, 1 passed (1 assertions) Duration: 0.10s |
思った以上の成果が得られました。ファイルはおろかテストも認識されています。
しかも正確なエラー付きです。
どうやら dataProvider メソッド を static で作って欲しいようです。
エラーに従うロボットになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <? 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_データプロバイダーのテスト($data, $expected) { $this->assertTrue(true); } } |
1 2 3 4 5 6 7 | root:/var/www/html/src# php artisan test tests/Unit/DataProviderTest.php PASS Tests\Unit\DataProviderTest ✓ データプロバイダーのテスト with data set "params" 0.06s Tests: 1 passed (1 assertions) Duration: 0.09s |
通りましたね!
どうやら dataProvider として使うメソッドは、static にしてあげれば求める挙動はしてくれそうです。
ひとまずは解決しましたが、「INFO No tests found.」の謎を追求してみたいと思います。
原因の追究
これまでの情報でわかっていることの中で立てられる仮説は、「dataProviderとして使うメソッドは static でなければならない」ということです。
ここで、一番最初の実行結果が参考になります。
1 2 3 | root:/var/www/html/src# php artisan test tests/Unit/DataProviderTest.php WARN Metadata found in doc-comment for method Tests\Unit\DataProviderTest::test_データプロバイダーのテスト(). Metadata in doc-comments is deprecated and will no longer be supported in PHPUnit 12. Update your test code to use attributes instead. INFO No tests found. |
御覧の通り、Doc コメントで dataProvider を使用するのは、まだ "非推奨" なだけなので WARN です。
ということは、dataProvider メソッドさえ static なら正常に実行できるのではないかと考えられます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <? 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_データプロバイダーのテスト($data, $expected) { $this->assertTrue(true); } } |
1 2 3 4 5 6 7 8 9 10 11 | root:/var/www/html/src# php artisan test tests/Unit/DataProviderTest.php WARN Metadata found in doc-comment for method Tests\Unit\DataProviderTest::test_データプロバイダーのテスト(). Metadata in doc-comments is deprecated and will no longer be supported in PHPUnit 12. Update your test code to use attributes instead. PASS Tests\Unit\DataProviderTest ✓ データプロバイダーのテスト with data set "params" 0.09s Tests: 1 passed (1 assertions) Duration: 0.14s |
仮説通り正常に実行できましたね。
しかしながら、なぜ static である必要があるのでしょうか。私の記憶とソースコードを見るに以前は static である必要はなかったはずです。
ということで調べてみました。
〇引用:https://docs.phpunit.de/en/10.5/writing-tests-for-phpunit.html#data-providers
原文
A data provider method must be public and static.
It must return a value that is iterable, either an array or an object that implements the Traversable interface.
翻訳
データプロバイダメソッドは、public かつ static でなければなりません。
反復可能な値(配列またはTraversableインターフェースを実装したオブジェクト)を返さなければなりません。
ということらしいです。変化についていきましょう。
さらに下記のような記述もありました。
原文
When a test depends on a test that uses data providers, the depending test will be executed when the test it depends upon is successful for at least one data set.
The result of a test that uses data providers cannot be injected into a depending test.
翻訳
テストがデータプロバイダを使用するテストに依存している場合、依存するテストは、依存するテストが少なくとも1つのデータセットで成功した場合に実行されます。
データプロバイダを使用するテストの結果は、依存するテストには注入されません。
適当なテストを入れたらエラーが出てきた理由はこれみたいです。
いわれてみたら「はい!仰る通りでございます!」というぐうの音も出ない正論パンチです。
テスト以前の部分で失敗してそれを前提としたテストしか存在しないなら「No tests found.」は至極当然です。
結論
dataProvider の対象メソッドは staticメソッド にしてください。
余談
なんで static である必要があるの? という疑問が出てきます。 (なぜおまえの感想なんだエンジニアならソースを出せと言われることに怯えて震えています。) おそらく「テストデータのテストからの独立性の担保」ではないかなと考えています。 再現性と他テストに影響を与えないことはテストにおいてとても重要なことであり、インスタンスの状態に依存しない純粋なデータを提供することを保証できます。 色々と公式のソースを漁ってみたのですが、static にしてね!というアップデートに際した情報は散見されました。 しかしながら、なぜ static にすることを強制しだしたのかという理由に関する部分は見つけられませんでした、、、 (ご存じの方いらしたらぜひご教示いただきたいです)