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]で指定した関数もちゃんとカバレッジが計測されていました。

