PHPUnitのバージョン上げようとして嵌った

環境

  • Laravel 5.3.x / Laravel 5.5.x の2つのアプリケーションが存在
  • PHP 7.2.x

やりたいこと

どちらも最新バージョンのPHPUnit(8.x)が使いたい

事象と原因

Laravel 5.3.xのアプリケーション

PHP Fatal error:  Class 'PHPUnit_Framework_TestCase' not found in application/path/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php on line 11

このエラーが発生

Laravel5.4からPHPUnitのクラス名の名前空間化?に対応したらしく、 以下の記述をするLaravel5.3でエラーが発生

use PHPUnit_Framework_TestCase;

abstract class TestCase extends PHPUnit_Framework_TestCase

Laravel5.4以降

use PHPUnit\Framework\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase

対応策

PHPUnitのバージョンを上げない

細かく言うと

  • vendor配下のモジュールのためオーバーライドする必要がある(と思う)
  • バージョンを上げることはwantであり、mustではない

Laravel 5.5.xのアプリケーション

PHP Fatal error:  Declaration of Illuminate\Foundation\Testing\TestCase::setUp() must be compatible with PHPUnit\Framework\TestCase::setUp(): void in application/path/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php on line 12

ググってもよく分からなくて、後輩に聞いたら教えてくれた。

phpunit.de

Return Type of Template Methods The methods listed below now have a void return type declaration:

PHPUnit\Framework\TestCase::setUpBeforeClass() PHPUnit\Framework\TestCase::setUp() PHPUnit\Framework\TestCase::assertPreConditions() PHPUnit\Framework\TestCase::assertPostConditions() PHPUnit\Framework\TestCase::tearDown() PHPUnit\Framework\TestCase::tearDownAfterClass() PHPUnit\Framework\TestCase::onNotSuccessfulTest() Your implementations of the methods listed above now must be declared void, too, otherwise you will get a compiler error.

この一文にびっくり「otherwise you will get a compiler error.」

ということで、上記に当てはまるメソッドに対して、

: void を記述したらエラーが解消された。

/**
 * Setup the test environment.
 *
 * @return void
 */
protected function setUp(): void
{

対応策

PHPUnitのバージョンを上げない

細かく言うと

  • Laravel5.3のときと同様に、vendor配下のモジュールのためオーバーライドする必要がある(と思う)
  • 既存のテストコードに対しても修正が必要で、意外と工数が掛かることが判明

既存のテストコードでのエラー

/**
 * XXXXXTest constructor.
 *
 * @param string|null $name
 * @param array       $data
 * @param string      $dataName
 */
public function __construct(string $name = null, array $data = [], string $dataName = '')
{

__constructをこう実装していたのだが、

PHP Fatal error:  Uncaught TypeError: Argument 3 passed to Tests\Feature\XXXXXTest::__construct() must be of the type string, integer given

エラーが発生してしまった。

/**
 * GetUserTest constructor.
 *
 * @param string|null $name
 * @param array       $data
 * @param             $dataName
 */
public function __construct(string $name = null, array $data = [], $dataName = '')
{

こう直したら動いたのだが、Warningが発生しててあまり綺麗とは言えなかった。

PHPUnit 8.0.4 by Sebastian Bergmann and contributors.

  Warning - The configuration file did not pass validation!
  The following problems have been detected:

  Line 26:
  - Element 'log', attribute 'logIncompleteSkipped': The attribute 'logIncompleteSkipped' is not allowed.

  Test results may not be as expected.


.........                                                           9 / 9 (100%)

Time: 3.07 seconds, Memory: 24.00 MB

補足

戻り値の型問題は、Laravel5.8で修正されているので、

Laravel5.7 以下ではPHPUnit8.xは使わない方がよさそう。という見解を得られた。

github.com