こんにちは!GameWithのサーバサイドエンジニアのkuromokaです!
先日、GameWithのサイトをPHP7.3にバージョンアップした記事を書きました。
ただPHPUnitのバージョンはそのまま4系を使い続けていて、4系だとPHP7に対応していないために次のような問題点がありました。
- 新規にPHP7.3のコードは書けるけどテストコードが書けない
- 既存のテストコードが書かれている箇所を、PHP7.3のコードに変更するとテストコードが失敗
そのため今回、現行の最新バージョンであるPHPUnit 8へのバージョンアップを行いました。
対応内容
そのままパッケージのバージョンを上げただけでは当然動かなかったので、次の対応を行いました。
DbUnitの変更
DB関連のテストコードでは、DbUnitというパッケージを使っています。今回の対応ではこれも合わせてバージョンアップをする必要がありました。
ただし本家のsebastianbergmann/dbunitは、更新がストップしているためにPHPUnit 8に対応していませんでした。そのためDbUnitの依存を外すことも考えたのですが、コード中で使われている箇所が多く断念しました。
どうしようか?といろいろと検索しているうちにforkされたパッケージがいくつかあるのを知り、一番スター数の多かったkornrunner/dbunitを使うことにしました。現行の最新バージョンの4.1.0なら、PHPUnit 8にも対応しています。
テストクラスの変更
次のクラスがPHPUnitとDbUnitで名前空間ベースに変更されていて、クラスが見つからないとエラーが出るため修正しました。
PHPUnit
PHPUnit_Framework_TestCase
→PHPUnit\Framework\TestCase
DbUnit
PHPUnit_Extensions_Database_TestCase
→PHPUnit\DbUnit\TestCase
PHPUnit_Extensions_Database_DataSet_YamlDataSet
→PHPUnit\DbUnit\DataSet\YamlDataSet
前後処理のメソッドへのvoidの追加
テストメソッド実行前の処理を書くsetUP()
など、PHPUnit\Framework\TestCase
でvoidが追加になったメソッドがあります。*1
そのため継承したテストケースのクラスでも同じように、voidを追加する必要がありました。
<?php class AppTest extends \PHPUnit\Framework\TestCase { - protected function setUp() + protected function setUp(): void { ・・・ } }
GameWithで書かれているテストコードでは次のメソッドが対象でした。
setUP()
→setUp(): void
tearDown()
→tearDown(): void
例外テストの変更
setExpectedException()
が廃止になっているため、expectException()
に変更をしました。
例外アノテーションの変更
@expectedException
のアノテーションでの例外テストはPHPUnit 9で消える予定のため、実行すると次のようなwarningメッセージが出てきます。そのため同様にexpectException()
への変更を行いました。
The @expectedException, @expectedExceptionCode, @expectedExceptionMessage, and @expectedExceptionMessageRegExp annotations are deprecated. They will be removed in PHPUnit 9. Refactor your test to use expectException(), expectExceptionCode(), expectExceptionMessage(), or expectExceptionMessageRegExp() instead.
無意味なテストの修正
「無意味なテスト」とは、ドキュメントの「リスクを伴うテスト」の章に書いてあるテストのことです。GameWithのテストコードではこの「無意味なテスト」が非常に多く今回の修正で一番大変な部分でした。オプションでチェック無効にもできるみたいですが、結局はコード負債として残ってしまうため一緒に直すことにしました。
https://phpunit.readthedocs.io/ja/latest/risky-tests.htmlphpunit.readthedocs.io
いろいろな「無意味なテスト」のパターンはあったのですが、たとえばreturnしない関数へのテストで、アサーションが何もないようなテストコードがありました。
実際のコードでは呼び出し後にモックの引数チェックなどが続いてたりしたのですが、肝心のアサーションがないのでThis test did not perform any assertions
というメッセージが出ていました。
<?php function void_func(): void { ・・・ }
<?php class AppTest extends \PHPUnit\Framework\TestCase { public function test_void_func() { void_func(); } }
このパターンのテストコードは、assertNull()
でNULLかどうかのアサーションを追加して対処しました。
<?php class AppTest extends \PHPUnit\Framework\TestCase { public function test_void_func() { $result = void_func(); $this->assertNull($result) } }
他の「無意味なテスト」の修正についても書くと、何日掛かっても書き終わらないので今回はこれだけにしておきます!
修正差分
今回のバージョンアップ対応を含めたPRは、Composerの定義ファイルの更新なども含まれていますが、
Files changed: 105
+2,471 −5,554
となかなかの大工事になりました。
まとめ
これまで書いてきた対応を行ったことで、最初に書いた問題点を解決することができました!
- 新規にPHP7.3のコードは書けるけどテストコードが書けない
- 既存のテストコードが書かれている箇所を、PHP7.3のコードに変更するとテストコードが失敗
と言いたかったのですが、GameWithではモックのフレームワークにAspectMockを使っていて、こちらもPHP7.3に対応したバージョンに上げる対応を別途行いました(泣)
現在は対応が完了して、上記の問題点は解決しています!
終わりに
GameWithのDeveloper向けTwitterアカウントを開設しました。
技術やブログの更新情報などを発信するので良かったらフォロー宜しくお願いします!
Tweets by gamewith_dev twitter.com
*1:網羅的に書いてあるページは見つけられなかったのですが、https://phpunit.readthedocs.io/en/latest/fixtures.html などを参考にしました。