Laravel5.7: テストの基本


親記事

Laravel 5.7で基本的なCRUDを作る - Qiita

ComposerのScripts経由でテストする

テストの実行にはvendor/内のPHPUnitを利用します。
下記のコマンドで実行できます。

PowerShell
# テストを実行
> vendor\bin\phpunit

これでもいいのですが、「テストするにはどのコマンドを使えばいいか」を他のメンバーにも分かりやすく伝えるために、ComposerのScriptsにコマンドを登録するのがいいと思います。
Composer公式ドキュメント: Writing custom commands

composer.json
 {
     "scripts": {
+        "test": "phpunit",
PowerShell
# テストを実行
> composer test

デフォルトのExampleTestを試す

まずは、tests/Feature/tests/Unit/の両方に初めから存在するExampleTestを実行します。
下記のように「OK」と表示されることを確認してください。

PowerShell
> composer test
> phpunit
PHPUnit 7.3.4 by Sebastian Bergmann and contributors.

..                                                                  2 / 2 (100%)

Time: 384 ms, Memory: 12.00MB

OK (2 tests, 2 assertions)

エラーになったら

私の場合はエラーになってしまいました。

PowerShell
> composer test
> phpunit
PHPUnit 5.7.21 by Sebastian Bergmann and contributors.

F.                                                                  2 / 2 (100%)

Time: 3.05 seconds, Memory: 10.00MB

There was 1 failure:

1) Tests\Feature\ExampleTest::testBasicTest
Expected status code 200 but received 404.
Failed asserting that false is true.

C:\...\vendor\laravel\framework\src\Illuminate\Foundation\Testing\TestResponse.php:75
C:\...\tests\Feature\ExampleTest.php:21

FAILURES!
Tests: 2, Assertions: 2, Failures: 1.
Script phpunit handling the test event returned with error code 1

ログを確認

上のメッセージだけでは詳細が分からないのでログを読みます。
ログの保存場所はconfig/logging.phpで設定されています。
デフォルトではstorage_path('logs/laravel.log')、つまりstorage/logs/にあります。
readouble.com: ログ

storage/logs/laravel-2017-06-25.log
[2017-06-25 01:47:06] testing.ERROR: ErrorException: Undefined index: HTTP_ACCEPT_LANGUAGE in C:\...\app\Http\Middleware\CheckLocale.php:31

自作のミドルウェアの31行目で、ユーザーの国・地域を判断するためにブラウザのHTTP_ACCEPT_LANGUAGEを取得しているのですが、テスト環境ではこれを取得できなかったせいでエラーとなっていたようです。
該当箇所を修正して解決しました。

特定のテストだけを実行する

--filterオプションで制限できます。
PHPUnit公式ドキュメント: フィルターパターンの例

Composerのスクリプトにオプションを渡すには--でつなぎます。
:link: Composer公式ドキュメント: Scripts

PowerShell
# tests/Feature/ExampleTest.php と
# tests/Unit/ExampleTest.php の両方が実行される
> composer test -- --filter 'ExampleTest'

# tests/Feature/ExampleTest.php だけを実行
# 正規表現なので \\ となっていることに注意
> composer test -- --filter 'Feature\\ExampleTest'

# tests/Feature/ExampleTest.php の testBasicTest だけを実行
> composer test -- --filter 'Feature\\ExampleTest::testBasicTest'

カバレッジを取得する

XAMPPにXdebugをインストール

Xdebug は PHPUnit 本体には組み込まれていません。 テストを実行したときに Xdebug がロードできないという notice が出る場合は、 Xdebug がインストールされていないかあるいはうまく設定できていないのでしょう。

PHPUnit公式ドキュメント: コードカバレッジ解析

XdebugがないとError: No code coverage driver is availableと表示されます。
XAMPPの場合はXdebugを追加しなければなりません。
下記に従ってください。
xdebugをwindowsのphpに設定する方法で悩んだ件 - Qiita

コマンドをComposerに登録する

カバレッジの結果はcoverage/フォルダ内にHTML形式で保存するようにします。
PHPUnit公式ドキュメント: コマンドラインオプション

カバレッジが不要な場合もあるので、composer testとはコマンドを別にします。

comopser.json
 {
     "scripts": {
         "test": "phpunit",
+        "cover": "phpunit --coverage-html coverage",
PowerShell
# テストし、カバレッジを取得する
> composer run-script cover

なお、クラウドサービス上でテストしたりカバレッジを取得する方法は別の記事で紹介しています。

coverageフォルダをGitの対象から外す

自動生成されるカバレッジの報告書をGitで管理しても意味がないので対象から外します。
下記を追加してください。

.gitignore
# テストのカバレッジを保存する場所
/coverage

カバレッジ取得の対象を細かくしぼる

デフォルトではapp/内の全てがカバレッジ取得の対象となってしまうので、開発で全く触れていないフォルダやファイルは除外するようにします。
[Laravel]はじめてのUnitTest
PHPUnit公式ドキュメント: XML 設定ファイル

phpunit.xml
    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./app</directory>

            <!-- 除外リストを追加する -->
            <exclude>
                <directory suffix=".php">./app/Console</directory>
                <directory suffix=".php">./app/Exceptions</directory>

                <!-- コントローラ -->
                <file>./app/Http/Controllers/Controller.php</file>
                <file>./app/Http/Controllers/FooController.php</file>

                <!-- ミドルウェア -->
                <file>./app/Http/Middleware/Authenticate.php</file>
                <file>./app/Http/Middleware/CheckForMaintenanceMode.php</file>
                <file>./app/Http/Middleware/EncryptCookies.php</file>
                <file>./app/Http/Middleware/TrimStrings.php</file>
                <file>./app/Http/Middleware/TrustProxies.php</file>
                <file>./app/Http/Middleware/VerifyCsrfToken.php</file>

                <!-- サービスプロバイダ -->
                <file>./app/Providers/BroadcastServiceProvider.php</file>
                <file>./app/Providers/EventServiceProvider.php</file>
                <file>./app/Providers/RouteServiceProvider.php</file>
            </exclude>
        </whitelist>
    </filter>