Laravel5.7: テストの基本

# 親記事
[Laravel 5.7で基本的なCRUDを作る - Qiita](https://qiita.com/sutara79/items/ef30fcdfb7afcb2188ea)


# ComposerのScripts経由でテストする
テストの実行には`vendor/`内のPHPUnitを利用します。
下記のコマンドで実行できます。

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

これでもいいのですが、「テストするにはどのコマンドを使えばいいか」を他のメンバーにも分かりやすく伝えるために、ComposerのScriptsにコマンドを登録するのがいいと思います。
:link: Composer公式ドキュメント: [Writing custom commands](https://getcomposer.org/doc/articles/scripts.md#writing-custom-commands)

```diff:composer.json
 {
     "scripts": {
+        "test": "phpunit",
```

```text:PowerShell
# テストを実行
> composer test
```


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

```text: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)
```


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

```text: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/`にあります。
:link: readouble.com: [ログ](https://readouble.com/laravel/5.7/ja/logging.html)

```text: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`オプションで制限できます。
:link: PHPUnit公式ドキュメント: [フィルターパターンの例](https://phpunit.de/manual/current/ja/textui.html#textui.examples.filter-patterns)

Composerのスクリプトにオプションを渡すには`--`でつなぎます。
:link: Composer公式ドキュメント: [Scripts](https://getcomposer.org/doc/articles/scripts.md#running-scripts-manually)

```text: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 がインストールされていないかあるいはうまく設定できていないのでしょう。

:link: PHPUnit公式ドキュメント: [コードカバレッジ解析](https://phpunit.de/manual/current/ja/code-coverage-analysis.html)

Xdebugがないと`Error: No code coverage driver is available`と表示されます。
XAMPPの場合はXdebugを追加しなければなりません。
下記に従ってください。
:link: [xdebugをwindowsのphpに設定する方法で悩んだ件 - Qiita](https://qiita.com/f_uto/items/bd5b2309ea415a6de1ca)

## コマンドをComposerに登録する
カバレッジの結果は`coverage/`フォルダ内にHTML形式で保存するようにします。
:link: PHPUnit公式ドキュメント: [コマンドラインオプション](https://phpunit.de/manual/6.5/ja/textui.html#textui.clioptions)

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

```diff:comopser.json
 {
     "scripts": {
         "test": "phpunit",
+        "cover": "phpunit --coverage-html coverage",
```

```text:PowerShell
# テストし、カバレッジを取得する
> composer run-script cover
```

なお、クラウドサービス上でテストしたりカバレッジを取得する方法は[別の記事](https://qiita.com/sutara79/items/2e4c77024364193c06cb)で紹介しています。

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

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

## カバレッジ取得の対象を細かくしぼる
デフォルトでは`app/`内の全てがカバレッジ取得の対象となってしまうので、開発で全く触れていないフォルダやファイルは除外するようにします。
:link: [[Laravel]はじめてのUnitTest](http://atuweb.net/201612_laravel-test-1ststep/)
:link: PHPUnit公式ドキュメント: [XML 設定ファイル](https://phpunit.de/manual/current/ja/appendixes.configuration.html#appendixes.configuration.whitelisting-files)

```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>
```