LaravelでControllerのテストをする

LaravelはControllerのテスト書きやすいと思います。ただ、ドキュメントがあまりなくて調べるのに少し苦労した記憶があります。そんなにいっぱいパターンがあるわけじゃないと思いますが、自分の場合はこうやってましたというのを晒しておきます。

通常のフォーム入力をテストする

まず基本的なところからで通常のフォーム入力です。

public function test登録できる()
{
    $user = User::create([...省略]);
    $this->actingAs($user); // 認証する

    $this->visit('/users/apply')
        ->see('入力画面')
        ->seeInField('your_name', '') // フィールド内の表示の確認
        ->seeIsSelected('prefecture', '') // セレクトボックスの場合
        ->type('山田太郎', 'your_name') // テキストボックスの入力
        ->select('tokyo', 'prefecture') // セレクトボックスの選択
        ->type('male', 'sex') // ラジオボタンの入力
        ->press('登録する')
		->seeStatusCode(200)
        ->dontSee('失敗しました')
        ->see('登録が完了しました');
}

チェックボックスは少し面倒でした。たとえば下記の例のように単一のnameで複数選択できるものの場合があると思います。

<input type="checkbox" name="hobbies[]" value="soccer" />
<input type="checkbox" name="hobbies[]" value="baseball" />
<input type="checkbox" name="hobbies[]" value="books" />

こういう場合は下記のように配列で$inputsに格納するようなメソッドを用意して対応する必要がありました。

public function test登録できる()
{
    $user = User::create([...省略]);
    $this->actingAs($user); // 認証する

    $this->visit('/users/apply')
        ->see('入力画面')
        ->storeArrayInput(['soccer', 'baseball'], 'hobbies') // チェックボックス
        ->press('登録する')
		->seeStatusCode(200)
        ->dontSee('失敗しました')
        ->see('登録が完了しました');
}

protected function storeArrayInput($values, $name)
{
    $this->inputs[$name] = $values;
    return $this;
}

ちなみにこのケースはチェックボックスだけでなく[](ブラケット)を利用する配列型の値に関して汎用的に利用する事ができます。なので、繰り返し領域のようなものがある場合も同じ形で対応します。

ネタ元はstack overflowです。

Laravel unit test with input with array name

バリデーションをテストする

ぼくの場合、バリデーションはFormRequestを使っていたのでControllerレベルでのテストが必須でした。上記のフォーム入力のテストの方法で地道にバリデーションを試してました。たとえばこんな感じです。

public function testバリデーションできる()
{
    $user = User::create([...省略]);
    $this->actingAs($user);

    $this->visit('/users/apply')
         ->type($this->createText(31), 'text1')
         ->type($this->createText(1501), 'text2')
         ->press('登録する')
         ->see('誤りがあります')
         ->see('30文字以下に')
         ->see('1500文字以下に')
         ->type($this->createText(30), 'text1') // createTextは自分で作ったメソッドです
         ->type($this->createText(1500), 'text2')
         ->dontSee('30文字以下に')
         ->dontSee('1500文字以下に')
         ->see('成功しました');
}

地道なんですが、やっぱりバグが見つかったりしますしリファクタリングした時にミスでエラーになってくれたりするのでやはり書いておくと重宝します。

Multi-Authしてる場合の認証

通常と同じようにloginAsを使うんですが第2引数にguardの名称を渡します。デフォルトのguardだと省略できるという事ですね。

$admin = Administrator::create([...省略]);
$this->actingAs($admin, 'admin');

REST APIをテストする

次にREST APIのテスト方法です。これもシンプルになっています。

public function testAPIで登録できる()
{
    $user = User::create([...省略]);
    $this->actingAs($user);

    $this->post("/api/users/apply", [
            'full_name' => '山田太郎',
            'sex' => 'male',
            'hobbies' => ['soccer', 'baseball'],
            'prefecture' => 'tokyo',
        ], [
            'Accept' => 'application/json'
        ])
        ->seeStatusCode(200)
        ->seeJson([
            'result' => 'ok',
        ]);
}

ちなみにseeJsonが面倒な場合は構造だけチェックするという物ぐさなメソッドも用意されています。上記の場合だと下記のようになります。

->seeJsonStructure([
    'result',
]);

こうして見るとあまり覚えることないですね。最初少し苦労してた気がしてたんですが気のせいだったかな…。