PHPUnit11でテストを実行すると、実行後の出力に「PHPUnit Deprecations」というメッセージが表示されるようになっていました。@test
などの慣れ親しんだアノテーションはPHPUnit12からサポート外となるようですので、新しいアトリビュートへ変更します。
PHPUnit12で削除される@アノテーション
OK, but there were issues! Tests: 28, Assertions: 64, PHPUnit Deprecations: 1.
こちらがテスト時に表示されたメッセージです。「PHPUnit Deprecations: 1」だけだと分かりにくいので、詳細内容も出力されるようにphpunit.xmlを少し修正します。
... <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd" bootstrap="vendor/autoload.php" colors="true" displayDetailsOnPhpunitDeprecations="true" //これを追加 > ...
phpunit
タグにdisplayDetailsOnPhpunitDeprecations="true"
を追加しました。これで再度テストを実行すると、以下のようなメッセージが出力されました。
There was 1 PHPUnit test runner deprecation: 1) Metadata found in doc-comment for method Tests\Unit\Models\UserModelTest::is_admin_check(). Metadata in doc-comments is deprecated and will no longer be supported in PHPUnit 12. Update your test code to use attributes instead.
メッセージによると、ドキュメントコメント内のアノテーションは非推奨とのこと。PHPUnit12ではサポート対象外となるため、テストのアノテーションは「アトリビュート」に書き換える必要があるようです。
アノテーション → アトリビュートの書き換え
今まで使っていたアノテーションの記述は、アトリビュートでは以下のように書き換えます。
-
@test
→#[Test]
-
@dataProvider
→#[DataProvider('データプロバイダ名')]
-
@covers
→#[CoversMethod('カバー対象のクラス', 'カバー対象メソッド')]
他のアトリビュートの記述はドキュメントで紹介されていますのでご参照ください。
基本的にはこれらを書き換えればいいだけなのですが、@covers
に関しては記述の位置が大きく変更となるためご注意ください。では具体的にどう変更になったか?というのを、以下のテストコードを使ってご紹介します。
変更前のテスト(アノテーション使用)
こちらがアノテーションを使用したユニットテストです。ドキュメントコメント内に@test
、@covers
、@dataProvider
を使用しています。
namespace Tests\Unit\Models; use App\Models\User; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; class UserModelTest extends TestCase { use RefreshDatabase; /** * @test * @covers App\Models\User::isAdmin * @dataProvider roleDataProvider */ public function is_admin_check(string $role, bool $expected): void { $user = User::factory()->create(['role' => $role]); $this->assertEquals($expected, $user->isAdmin()); } public static function roleDataProvider(): array { return [ 'role = admin' => [ 'role' => 'admin', 'expected' => true ], 'role = user' => [ 'role' => 'user', 'expected' => false ], 'role = role' => [ 'role' => 'editor', 'expected' => false ], ]; } }
変更後のテスト(アトリビュート使用)
以下が、アトリビュートに書き換えた後のテストになります。
namespace Tests\Unit\Models; use App\Models\User; use Illuminate\Foundation\Testing\RefreshDatabase; use PHPUnit\Framework\Attributes\CoversMethod; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; use Tests\TestCase; #[CoversMethod(User::class, 'isAdmin')] class UserModelTest extends TestCase { use RefreshDatabase; #[Test] #[DataProvider('roleDataProvider')] public function test_is_admin_check(string $role, bool $expected): void { $user = User::factory()->create(['role' => $role]); $this->assertEquals($expected, $user->isAdmin()); } public static function roleDataProvider(): array { return [ 'role = admin' => [ 'role' => 'admin', 'expected' => true ], 'role = user' => [ 'role' => 'user', 'expected' => false ], 'role = role' => [ 'role' => 'editor', 'expected' => false ], ]; } }
まず、use
で#[Test]
などの各属性に対応するクラスをインポートする必要があります。そして、#[Test]
・#[DataProvider()]
はアノテーションと同様テストケースの直前に配置します。
一番大きな変更である@covers
の位置ですが、アトリビュートではクラス宣言の直前に置く形になります。
ドキュメントにもあるように、#[CoversMethod()]
は各テストケースではなくテストクラスに指定する必要があります。
最初このルールに気が付かず、@covers
と同じように各テストケースの前に#[CoversMethod()]
を配置したところ以下のようなエラーが発生しテスト失敗となりました。
$ ./vendor/bin/phpunit An error occurred inside PHPUnit. Message: Attribute "PHPUnit\Framework\Attributes\CoversMethod" cannot target method (allowed targets: class)
ちゃんとエラーが出てくれたので、気がつけてよかったです。
改めてテストを実行
アトリビュートへの書き換えが正しくできているか、再度テストを実行してみます。
$ ./vendor/bin/phpunit OK (28 tests, 64 assertions)
Deprecationsのメッセージが出なくなりました。テスト数やアサーションの数も同じなので、書き換えは問題なくできたようです。
カバレッジの出力を確認
#[CoversMethod()]
の動作確認も兼ねて、カバレッジの出力も見てみます。私の環境ではpcovを使用しています。まだの方はインストールと、php.iniにて以下を設定ください。
extension=/path/to/your/pcov.so pcov.enabled=1 pcov.directory=/path/to/your/project
では、カバレッジのオプションをつけてテストを実行します。
$ ./vendor/bin/phpunit --coverage-html coverage
実行後、プロジェクトルートのcoverageディレクトリにhtmlファイルが生成され、#[CoversMethod]
で指定した関数もちゃんとカバレッジが計測されていました。