🗂

他のテストのデータが干渉して、テストが通らないときの解決策

2021/06/23に公開

Laravelのテストで use RefreshDatabase をすると毎回テスト用データベースをロールバックしてくれるため、テストごとにテストデータを入れて検証することができる。

しかし、 use RefreshDatabase をしてもうまくテストデータがリセットされてないっぽい現象がおきてしまった。

現象を整理する

このようなテストファイルがあるとする。
なるべくかんたんな例にするために、ユーザーを作成するAPIのテストをイメージして作った。

<?php

namespace Tests\Feature;

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class UserCreateTest extends TestCase
{
    use WithFaker;

    /**
     * ユーザー作成テスト
     */
    public function testCreateUser()
    {
        $admin = Admin::factory()->create();
        $this->actingAs($admin);
	
	$param = ['name' => $this->faker->name()];
        $response = $this->post('/api/user', $param);
        $response->assertStatus(201);

        $this->assertDatabaseHas('users', [
            'name' => $param['name']
        ]);
	
	$this->assertDatabaseCount('users', 1);
    }
}

このファイルを実行すると、普通なら成功するのだが、僕の場合はassertDatabaseCountもところで「テーブルに2個レコードがあるよー」とエラーになった。

原因はおそらく他のテストファイルで use RefreshDatabase を記述していないファイルがあったことなのだが、諸事情でその原因元のファイルに use RefreshDatabse を記述することができない。

解決策は、** 「テストファイル内で phpartisan migrate:fresh を実行すること!」** です。

やや強引ですが、解決しちゃうのでやってみます。

テストファイル内で migrate:freshを実行する

Laravelのテストで使われているPHPUnitでは、 setUpメソッドとtearDownメソッドがある。
setUp メソッドではテストファイル内の各テストが行われる前に実行されるメソッドで、 tearDown は各テストが行われた後に実行されるメソッドである。

僕の場合は、 setUpメソッドでこのようにマイグレーションを実行したらうまくいきました。

protected function setUp(): void
{
    parent::setUp();
    $this->artisan('migrate:fresh');
}

各テストの前に実行されているのでやや冗長かもしれませんが、一旦の回避策としてこれでいけました。

僕はまだ試していないですが、 setUpBeforeClasstearDownAfterClass というメソッドでテストごとではなく、テストが記述されているクラスの前後で処理を実行できるようなのでこちらでも良いかもしれません。

テストデータで変だな〜って思ったら $this->artisan('migrate:fresh'); を試してみてください!

Discussion