第14回: HTTPテストのベストプラクティス — `assertStatus(200)` だけで安心していませんか?

章: 第7章: テスト拡張と品質自動化

assertStatus(200) で満足しているテストは、「リクエストがおそらく到達した」ことを確認しているだけです。その後のDBの状態・レスポンスのJSON構造・リダイレクト先まで検証することで初めて「機能が正しく動いた」と言えます。

LaravelのHTTPテストはブラウザ層からリクエストを発行してレスポンスまで検証することができます。ルーティング・ミドルウェア・認証の組み合わせを一度にテストできる強力な機能です。

なぜHTTPテストの充実度が重要なのか

簡素なテストだけでは次の問題を捕捉できません。

  • 入力値のバリデーションエラーが正しく返るか(422 vs 302)
  • 未認証ユーザーが操作できないか(401 vs 403)
  • DBに正しくデータが保存されたか

チェックポイント: HTTPテストの会んは「ステータスコード」「DBの状態」「レスポンス構造」の3層検証です。

assertStatusだけ vs 充実した検証

検証項目 assertStatusのみ 充実したテスト
HTTPステータス
DBの状態変化
JSONレスポンスの構造
リダイレクト先
認可拒否

実装例


<?php
it('未認証ユーザーは投稿できない', function () {
    $response = $this->post('/posts', ['title' => 'x', 'body' => 'y']);
    $response->assertRedirect('/login');
});

it('認証ユーザーは投稿できる', function () {
    $user = User::factory()->create();
    $response = $this->actingAs($user)->post('/posts', ['title' => 'ok', 'body' => 'body']);
    $response->assertRedirect('/posts');
    $this->assertDatabaseHas('posts', ['title' => 'ok']);
});

まとめ & 次のステップ

  • assertRedirect() / assertJson() / assertDatabaseHas() を組み合わせて完全な検証を行う
  • actingAs($user) で認証済みテスト、引数なしで未認証テスト ― 導内が簡潔
  • assertUnprocessable() で422バリデーションエラーを要素単位で確認できる
  • withHeaders() withCookies() で現実のリクエストを再現し、たった2件から全体の機能を対象にできる

次回は 第15回: Repository層のテスト戦略 で、永続化ロジックの契約を固定するテスト設計を学びます。最初は少し難しく見えても、順番に確認すればちゃんと身についていきます。

今日の記事のポイント

HTTPテストは入力・認可・レスポンスを一連で固定するのがポイントです。

この記事が大事な理由

コントローラ単体では見えない実際の挙動を、ルーティング込みで検証できるからです。

ここは「どの場面で使うのか」を結びつけると理解しやすくなります。実際のコードを動かしながら、少しずつ慣れていきましょう。

よくあるつまずき

assertStatusだけで終えず、DB状態やJSON構造まで確認していきましょう。

「HTTPテストのベストプラクティス」でつまずくときは、知識不足というより「確認の順番」が曖昧なことが多いです。最初に観点を固定すると、理解が一気に進みやすくなります。

整理しやすい観点は次の3つです。

  • 何を守るテストかを明確にする: 仕様固定か実装詳細かを先に決める
  • テスト粒度を揃える: FeatureとUnitの責務を混ぜない
  • 壊れやすい箇所から優先する: 変更頻度の高いユースケースに先に網をかける

小さく検証するときは、次の順番で進めると詰まりにくくなります。

1. 「HTTPテストのベストプラクティス」に直結する主要ケースを3件だけ先に作る

2. 失敗ケースを1件追加し、期待するエラーを明示する

3. リファクタ後に同じテストが通ることを確認する

「HTTPテストのベストプラクティス」は、守りたい仕様を言語化してから書くと品質が安定します。

実際のコードのサンプル

まずは最小構成で動きを確認していきましょう。


<?php
it('未認証ユーザーは投稿できない', function () {
    $response = $this->post('/posts', ['title' => 'x', 'body' => 'y']);
    $response->assertRedirect('/login');
});

it('認証ユーザーは投稿できる', function () {
    $user = User::factory()->create();
    $response = $this->actingAs($user)->post('/posts', ['title' => 'ok', 'body' => 'body']);
    $response->assertRedirect('/posts');
    $this->assertDatabaseHas('posts', ['title' => 'ok']);
});

この記事で身についたこと

HTTPテストは入力・認可・レスポンスを一連で固定するのがポイントであることがわかりました。

今日のまとめ

HTTPテストのベストプラクティスは、Laravelをより深く使うための大切な知識です。完璧を目指しすぎず、手を動かしながら少しずつ使える形にしていきましょう。

「HTTPテストのベストプラクティス」を学ぶときは、実装前に「何を楽にしたいのか」「どこで失敗しやすいか」「確認結果をどう残すか」を先に言葉にしておくと理解が安定します。短いメモでも、次回の見直し時に判断材料として大きく効いてきます。

学習メモ

  • サンプルをそのまま実行したあと、値や条件を1つだけ変えて結果の違いを見ていきましょう。
  • 「HTTPテストのベストプラクティス」について、今日の気づきを1行で残しておくと次回の理解がかなり速くなります。
  • 実務に置き換えるならどの機能に使えるかを1つ書き出しておくと、学びが定着しやすくなります。

Related Articles