2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Laravel Feature TestにPHPDocで「Why」を残す:テストの意図を読みやすくする

2
Last updated at Posted at 2026-08-24

Laravel / PHPUnit のFeature Testを書いていると、テストメソッド名だけでも「何を確認しているか」はある程度分かります。
しかし、なぜそのテストが必要なのかなぜその検証方法を選んだのかまでは、メソッド名だけでは伝わらないことがあります。

この記事では、実際のLaravel Feature Testを題材に、PHPDocで「Why」を残す考え方を整理します。

目次


環境

  • PHP 8.4
  • Laravel 13
  • Laravel Breeze
  • PHPUnit
  • Laravel Sail

PHPDocとは

PHPでは複数行コメントとして、

/*
 * コメント
 */

を書くことができます。

その中でも、次のように/**から始まる形式はDoc Comment / DocBlockとして使われます。

/**
 * コメント
 */

PHP公式マニュアルでは、PHPが複数行コメントをサポートしていることが説明されています。

また、PHPUnitではDocBlockが歴史的にテストのメタデータ用途にも使われてきました。PHPUnit 12では、その用途でのAnnotationサポートは削除され、メタデータにはAttributesを使用します。一方、Doc Comment自体は、コードの意図や設計上の理由を説明するコメントとして利用できます。

参考:


テストメソッド名だけでは足りないことがある

例えば次のテスト名を見ます。

public function test_new_users_receive_email_verification_notification(): void

この名前だけでも、

新規ユーザーがメール認証通知を受け取ることを確認する

という「What」は分かります。

しかし、このテストが存在する理由までは完全には分かりません。

今回の実装では、

会員登録
↓
Registeredイベント
↓
Laravel標準のVerifyEmail通知
↓
メール認証

というメール認証フローを保証したいという背景があります。

そこでPHPDocで、

/**
 * 会員登録時にLaravel標準のメール認証通知が送信されることを保証する。
 */
public function test_new_users_receive_email_verification_notification(): void

と残します。

テスト名が「何を確認するか」、PHPDocが「なぜ保証する必要があるか」を補う形です。


WhatコメントとWhyコメントの違い

Whatだけのコメント

/**
 * メール認証通知をテストする。
 */

これはコードを読めば分かる内容です。

Notification::assertSentTo(
    $user,
    VerifyEmail::class,
);

を見れば、メール認証通知を確認していることは分かります。

Whyまで説明するコメント

/**
 * 会員登録時にLaravel標準のメール認証通知が送信されることを保証する。
 */

こちらは、

会員登録フローの一部として、この通知が欠けるとメール認証自体が成立しない

というテストの存在理由が読み取りやすくなります。

コメントを書くなら、コードを日本語に翻訳するだけではなく、そのテストが守っている仕様や意図を書く方が価値があります。


実例1:会員登録画面の初期状態

次のテストでは、会員登録画面の入力欄、ラベル、ARIA属性、エラー要素を確認しています。

public function test_registration_screen_can_be_rendered(): void
{
    // ...
}

PHPDocを付けるなら、

/**
 * 会員登録画面の初期表示で入力欄とラベルが正しく関連付けられ、
 * エラーがない状態では不要なARIA属性やエラー要素が表示されないことを保証する。
 */

とできます。

ポイントは単に、

会員登録画面が表示される

だけではなく、

正常時に誤ったエラー状態を支援技術へ伝えない

という意図まで残していることです。


実例2:バリデーションエラーとARIA属性

対象テスト:

public function test_registration_validation_errors_have_accessible_aria_attributes(): void
{
    // ...
}

PHPDoc例:

/**
 * 会員登録のバリデーションエラーを支援技術へ正しく伝えるため、
 * 対象入力欄に必要なARIA属性が付与され、他の入力欄へ誤って影響しないことを保証する。
 */

このテストでは単にエラーメッセージが表示されるだけでなく、

  • aria-invalid
  • aria-describedby
  • エラー要素
  • 他フィールドへの誤ったARIA属性付与

などを確認しています。

そのためPHPDocにも、

支援技術へ正しく伝える
他の入力欄へ影響しない

という「Why」を含めると、テストの役割が明確になります。


実例3:正常な会員登録

対象テスト:

public function test_new_users_can_register(): void
{
    // ...
}

PHPDoc例:

/**
 * 正常な入力で会員登録でき、登録後にログイン状態となって
 * アプリケーションのホームへ遷移できることを保証する。
 */

ここで「認証済み」と書かないのが重要です。

Laravel Breezeのメール認証を有効にした場合でも、

登録直後
↓
ログイン済み
↓
メールアドレスはまだ未認証

という状態があり得ます。

そのため、

認証済みセッション

ではなく、

ログイン状態

と書く方が正確です。

コメントも実装の現在状態に合わせて書く必要があります。


実例4:メール認証通知

実際に追加したテストです。

/**
 * 会員登録時にLaravel標準のメール認証通知が送信されることを保証する。
 */
public function test_new_users_receive_email_verification_notification(): void
{
    Notification::fake();

    $this->post('/register', [
        'name' => 'Test User',
        'email' => 'test@example.com',
        'password' => 'password',
        'password_confirmation' => 'password',
    ]);

    $user = User::where('email', 'test@example.com')->firstOrFail();

    $this->assertNull($user->email_verified_at);

    Notification::assertSentTo(
        $user,
        VerifyEmail::class,
    );
}

このテストでは、

会員登録
↓
email_verified_at は null
↓
VerifyEmail通知は送信される

という状態を保証しています。

PHPDocを読むだけでも、

Laravel標準のメール認証フローを守るためのテスト

だと理解できます。


private helperにもPHPDocを書く

テストメソッドだけでなく、テスト用helperにも「Why」が有効です。

例えば、

private function createXPath(string $html): DOMXPath

には、

/**
 * 文字列一致へ依存せず、対象DOM要素自身の属性を検証するためXPathを生成する。
 */

というPHPDocを付けています。

これは良いWhyコメントです。

単に、

XPathを作る

ではなく、

なぜXPathを使うのか
→ HTML文字列の単純一致ではなく、対象DOM要素自身を確認したいから

という設計理由を説明しています。


getSingleElementById()にもWhyを残す

例えば次のhelperがあります。

private function getSingleElementById(DOMXPath $xpath, string $id): DOMElement
{
    $elements = $xpath->query(sprintf('//*[@id="%s"]', $id));

    $this->assertNotFalse($elements);
    $this->assertCount(1, $elements);

    $element = $elements->item(0);
    $this->assertInstanceOf(DOMElement::class, $element);

    return $element;
}

この処理を日本語に翻訳するだけなら、

/**
 * 指定IDの要素を取得する。
 */

でも間違いではありません。

ただし、これではassertCount(1, ...)を行う理由が伝わりません。

Whyまで含めるなら、

/**
 * 重複IDや対象要素の欠落を見逃さず、ARIA属性などを対象要素自身で検証するため、
 * 指定IDの要素が1件だけ存在することを確認してDOMElementとして返す。
 */

と書けます。

これなら、

なぜ1件だけと確認するのか
↓
HTMLのID重複・欠落を見逃さないため

なぜDOMElementを返すのか
↓
ARIA属性などを要素単位で検証するため

まで分かります。


PHPDocを付けるときに意識したいこと

コードをそのまま日本語にしない

避けたい例:

/**
 * ユーザーを作成してPOSTしてリダイレクトを確認する。
 */

コードを読めば分かります。

守っている仕様を書く

良い例:

/**
 * メール未認証ユーザーからの公開レビュー投稿を防ぐため、
 * 認証案内画面へリダイレクトされ、レビューが保存されないことを保証する。
 */

このコメントなら、

なぜこのテストが存在するのか

が分かります。

実装詳細を書きすぎない

例えば、

EnsureEmailIsVerifiedのhandle()がredirectToRoute()を呼ぶことを保証する

のようにLaravel内部実装へ寄りすぎると、フレームワーク内部変更に弱いテスト説明になります。

アプリケーション側の仕様として、

未認証ユーザーはレビュー投稿できない

と書く方が読みやすくなります。


PHPDocは全部のテストに必要なのか

必ずしもPHPの言語仕様やPHPUnitが、すべてのテストメソッドへPHPDocを書くことを要求しているわけではありません。

例えば、

public function test_login_screen_can_be_rendered(): void

のようにテスト名だけで十分に意図が伝わるケースもあります。

ただし、プロジェクトで、

  • セキュリティ上の理由
  • アクセシビリティ上の理由
  • 回帰防止の理由
  • 一見すると不要に見えるAssertion
  • 独自helperを使う理由

などを重視している場合、Whyコメントを残す価値があります。

特に複雑なFeature Testでは、

何をしているか

より、

なぜそれを保証する必要があるか

の方が、数か月後に読み返したときに役立ちます。


今回の整理

テストコードでは、

テストメソッド名
↓
何を確認するか

PHPDoc
↓
なぜそれを保証する必要があるか

テストコード
↓
どうやって確認するか

と役割を分けると読みやすくなります。

例えば、

/**
 * メール未認証ユーザーからの公開レビュー返信を防ぐため、
 * 認証案内画面へリダイレクトされ、返信が保存されないことを保証する。
 */
public function test_unverified_user_cannot_store_review_comment(): void
{
    // Arrange / Act / Assert
}

を見ると、

What
未認証ユーザーはレビュー返信できない

Why
未認証アカウントから公開返信を作成させないため

How
リダイレクトとDB未保存をFeature Testで確認

が分かります。

PHPDocを単なる説明文ではなく、テストの設計意図を残す場所として使うと、Feature Test全体が読みやすくなりました。


関連記事

この内容は、次の記事と分けて相互リンクすると整理しやすくなります。

この記事は「PHPDoc / Whyコメント」、Feature Test記事は「テストコードの書き方」、英単語集は「テスト名の読み方」と役割を分けます。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?