はじめに

前回の実装のテストを書いたのでメモ。LaravelではアプリケーションにHTTPリクエストを送信し、出力内容をチェックしたりフォームに入力したりリンクやボタンをクリックするようなテストを書くことができる。

データベース設定

.env.testing にテスト用データベースの接続設定を書く。

モデルファクトリーの追加

テストを実行する際にあらかじめデータを入れておきたい場合の便利な機能。database/factories/ModelFactory.php に設定を追加する。

$factory->define(App\Sample::class, function (Faker\Generator $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
    ];
});

テストから以下のように使用する。

$sample = factory(App\Sample::class)->create();
$samples = factory(App\Sample::class, 3)->create(); // 件数を指定して複数生成する
$sample = factory(App\Sample::class)->make(); // DBに保存しない

テストファイルの生成と実行

テストファイルの作成

$ php artisan make:test SampleTest

実行

$ ./vendor/bin/phpunit

テスト後のデータベースリセット

テスト後にデータが残ったままだと色々影響があるのでリセットしたい、というのをLaravelでは用意されているトレイトを使用するだけでできる。

use DatabaseMigrations; // マイグレーションを使用する
use DatabaseTransactions; // トランザクションを使用する

今回はマイグレーションを使ってないのでuse DatabaseTransactions; を使用した。

テスト

一覧表示

public function testIndex()
{
    $samples = factory(App\Sample::class, 2)->create(); // テストデータ2件作成

    $this->visit('sample') // 一覧画面にアクセス
        ->see('Sample') // 画面に `Sample` が表示されている
        ->see($samples[0]->name)->see($samples[0]->email) // テストデータ1件目が表示されている
        ->see($samples[1]->name)->see($samples[1]->email) // テストデータ2件目が表示されている
        ->type($samples[0]->name,'name') // 検索フォームの名前欄にテストデータ1件目の名前を入力
        ->press('検索') // 検索ボタンを押す
        ->see($samples[0]->name) // テストデータ1件目が表示されている
        ->dontSee($samples[1]->name); // テストデータ2件目は表示されない
}

新規作成(バリデーションエラー)

public function testCreateNG()
{
    $this->visit('sample/create')
        ->type('','name')
        ->type('','email')
        ->press('作成')
        ->see('nameは必須です。')
        ->see('emailは必須です。');
}

新規作成(成功)

public function testCreateOK()
{
    $this->visit('sample/create')
        ->type('hoge','name')
        ->type('hoge@hoge.com','email')
        ->press('作成')
        ->seePageIs('/sample') // 一覧画面に遷移した
        ->see('hoge')
        ->see('hoge@hoge.com');
}

詳細画面

public function testShow()
{
    $sample = factory(App\Sample::class)->create();

    $this->visit('sample')
        ->click($sample->name) // 一覧画面の名前をクリックすると詳細画面に遷移する
        ->seeRouteIs('sample.show', ['sample' => $sample->id]) // ルーティングから遷移先の妥当性を検証
        ->see($sample->name);
}

編集

public function testEditOK()
{
    $sample = factory(App\Sample::class)->create();
    $new_name = 'new_name';

    $this->visit('sample')
        ->see($sample->name)
        ->click('編集')
        ->seeRouteIs('sample.edit', ['sample' => $sample->id])
        ->type($new_name,'name')
        ->press('編集')
        ->seePageIs('/sample')
        ->see($new_name) // 編集後の名前が表示されている
        ->dontSee($sample->name); // 編集前の名前は表示されていない
}

削除

public function testDeleteOK()
{
    $sample = factory(App\Sample::class)->create();

    $this->visit('sample')
        ->see($sample->name)
        ->press('削除')
        ->seePageIs('/sample')
        ->dontSee($sample->name);
}

補足

今回は画面に表示されているかどうかでデータが登録されていることを確認したけど、

$this->seeInDatabase('samples', [
    'email' => 'hoge@example.com'
]);

とすればデータベースを直接参照することもできる。