Laravel 8.5 PHPUnit テスト で Error: Call to a member function make() on null が発生した話

独自にsetUP()メソッドをオーバーライドしたときは、parent::setUp()メソッドをコールする必要がある

今回のケースでは、独自に setUp() メソッドを実装したのに、 parent::setUp() をコールしていなかったことが原因でした。

ドキュメントには、以下の記述があります。

If you define your own setUp / tearDown methods within a test class, be sure to call the respective parent::setUp() / parent::tearDown() methods on the parent class.

もし、あなた独自の setUp / tearDown メソッドをテストクラスに書くときは、それぞれの親クラスについて parent::setUp() / parent::tearDown() をコールすることを忘れないでください。

https://laravel.com/docs/8.x/testing#creating-and-running-tests

自作した setUp() メソッドの内側で parent::setUp() をコールすることで解消しました。

<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class UserTest extends TestCase
{
    protected function setUp():void {
        parent::setUp(); //この行を追記する必要がありました。
        //独自の準備処理を親クラスの setUp() 処理のあとに行う
    }
    protected function tearDown():void {
        //独自の後片付け処理を親クラスの tearDown() 処理の前に行う
        parent::tearDown();
    }

    /**
     * A basic feature test example.
     *
     * @return void
     */
    public function testExample()
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }
}

なお、 tearDownメソッドを用意する場合には、 同様に parent::tearDown() が必要とのことです。

もっと詳しく

今回のケースでは、独自に setUp() メソッドを用意したにもかかわらず、 以下のようにparent::setUp() をコールしていませんでした。

<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class UserTest extends TestCase
{
    protected function setUp():void {
        //parent::setUp();を書き忘れている。
        //独自の準備処理を親クラスの setUp() 処理のあとに行う
    }
    /**
     * A basic feature test example.
     *
     * @return void
     */
    public function testExample()
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }
}

この状態では、 $this->get('/') をコールしたときにエラーが発生しました。

1) Tests\Feature\UserTest::testExample
Error: Call to a member function make() on null

/var/www/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:498
/var/www/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:292
/var/www/tests/Feature/UserTest.php:21

Laravel では、自動テストに便利な機能を独自に用意してくれています。

今回のコードの $this->get('/') もその一つです。

artisan make:test コマンドで作成したテストクラスでは、このような便利機能を使う準備がされています。

php artisan make:test UserTest

このテストクラスには、初期状態では setUp() メソッドが存在していません。

この状態では、PHPUnit は親クラスの setUP() メソッドを実行します。これにより、便利な機能がいくつか準備されます。

しかし、 setUp() メソッドを独自に実装した場合は、親クラスで行うはずの処理が行われません。

これを解消するために、手作業で親クラスの setUp() メソッドをコールする記述が必要となります。