Laravelのテストについて初心者なりに理解した事をまとめた

## この記事について
[株式会社Re:Buildアドベントカレンダー Advent Calendar 2020](https://qiita.com/advent-calendar/2020/rebuild)の14日目の記事です！

最近業務でテストを書くことが多くなり、雰囲気でテストを書いてるのはよくないな〜と感じたので、自分の勉強のために記事を書きました！ほとんど忘備録のようなもので内容も初歩的なことばかり書いていますが、誰かのお役に立てたら嬉しいです:fist:

## この記事でまとめたこと
- テストはなぜ書く必要があるのか
- Laravelで用意されているテストの種類
- UnitテストとFeatureテストについて、それぞれの違い
- テストの環境、プロジェクトの環境はどこで設定されているのか
- `phpunit.xml`で使われているタグの意味（超絶ふんわり）

## テストはなぜ書く？
バグの発見、修正、リファクタリングをしやすくする為！
Laravelをインストールすると、phpunitがデフォルトでインストールされているので、すぐテストを書くことができる。

## Laravelで用意されているテストの種類
`tests`ディレクトリ配下に2種類のディレクトリが有り、1つはUnitテスト(単体テスト)、もう1つはFeatureテスト(機能テスト)の2つがある。
また、パッケージを追加することでBrowserテスト(ブラウザテスト)も使えるようになる。
合計3種類のテストがLaravelでは使える！

## Unitテストとは？
モデルの中に書かれているメソッド、アトリビュート、リレーション等の単体のメソッドが、想定通りの正しい値を返せているかを確認するテスト。

複雑なロジックが書かれたメソッドやhasManyThroughで色々テーブルやキーを指定したリレーションはテストした方が安心できるので出来れば書いた方が良さそう。

逆にbelongsToやhasOneなど、何が返ってくるか分かるリレーションはテスト無しでも問題なさそう。（と先輩から聞いた）

## Featureテストとは？
Controllerのアクションメソッドに対して行うテスト。

機能テストと呼ばれているように、様々なパターンのrequest・responseに対して、モデルで作成したリレーションやメソッドがController内部で動き、最終的に正しい値がdatabaseにセットされているかresponseでフロントに返されているかなどを確認する為に用いられている。

考えられる様々なパターン（NULLの場合、何か特定の文字が含まれた場合等）に対してテストする必要があるので、1アクションメソッドにつき1つのテストとは限らず複数のテストを書くこともある。

## テストの設定はどこでされている？  
Laravelをインストールした際に`php.xml`ファイルもデフォルトでインストールされていて、そのファイルの中の```<php></php>```で括られている箇所によって決定する。

```php:phpunit.xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
         bootstrap="vendor/autoload.php"
         colors="true">
    <testsuites>
        <testsuite name="Unit">
            <directory suffix="Test.php">./tests/Unit</directory>
        </testsuite>

        <testsuite name="Feature">
            <directory suffix="Test.php">./tests/Feature</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./app</directory>
        </whitelist>
    </filter>
    <php>
        <server name="APP_ENV" value="testing"/>
        <server name="BCRYPT_ROUNDS" value="4"/>
        <server name="CACHE_DRIVER" value="array"/>
        <server name="MAIL_DRIVER" value="array"/>
        <server name="QUEUE_CONNECTION" value="sync"/>
        <server name="SESSION_DRIVER" value="array"/>
    </php>
</phpunit>
```
## そもそもプロジェクトの設定はどこでされている？
`src > config > database > connections`の中に記載された内容で決まる。
例えば、conectionsにこう書いて↓

```php:database
'connections' => [
 ~~中略~~
        'mysql' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
            ]) : [],
        ],
```

`env`ファイルに以下のように書くと

```php:env
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=root
```
`database`ファイルの`connections`の```mysql```を参照するようになり、`env`ヘルパ関数によって`env`ファイル内で指定した文字(`DB_HOST=db`の「`db`」部分など)が`databese`ファイルで認識されるようになって、実行環境が決まるようになるみたい。
 
ちなみに、`.env.testing`ファイルを作成すると```database```ファイルの内容ではなく```.env.testing```ファイルの内容で実行環境を決めることができる。

`phpunit.xml`でそれを実行しているのが以下の行↓

```php:phpunit.xml
<server name="APP_ENV" value="testing"/>
```
実行環境は```.env```ファイルの```APP_ENV```変数により決定するので、優先的に```.env.testing```ファイルを参照し、あればその内容を設定するんだと思う。
参考：https://readouble.com/laravel/6.x/ja/configuration.html

もし以下のような行を追加すると`database`ファイルの`connection`の`hogehoge`を見にいくようになる。

```php:phpunit.xml
<server name="DB_CONNECTION" value="hogehoge"/>
```
`.env.testing`ファイルと上の行がどちらもある場合はどっちが優先になるのかはわからなかった、、、

## phpunit.xmlのそれぞれのタグの意味
### `<?xml version="1.0" encoding="UTF-8"?>`
XMLファイルだよ〜の宣言？（HTMLでいうと<!DOCMENT~~~~ >的な）

### `<phpunit></phpunit>`
PHPUnitの機能を設定するために使われてるタグ？

### `<testsuites></testsuites>`
テストスイートをグルーピングするタグ。（HTMLだと`<div></div>`とか`<ul></ul>`のようなイメージ）

### `<testsuite></testsuite>`
テストの設定ができるタグ。testsuiteのnameに設定した名前はテスト名として扱われ、そのテスト名ごとにテストが実行できる。

### `<directory></directory>`
名前の通りディレクトリを示すタグ。

### `<filter></filter>`
コードカバレッジを計測するために使用されるタグ。
コードカバレッジとは： コード網羅率のこと。コードカバレッジではホワイトボックステストが行われる。

### `<whitelist></whitelist>`
ホワイトリストの設定に使用されるタグ。ホワイトリストの設定をすると、PHPUnitに対してどのソースコードファイルをコードカバレッジレポートに含めるかを指定できる。`「addUncoveredFilesFromWhitelist="true"」`と書くと、ホワイトリスト上のすべてのファイルをコードカバレッジレポートに含められる。
肝心のコードカバレッジレポートはいったいなんなのかよくわからなかった、、、

### `<php></php>`
PHPの設定や定数、グローバル変数などの設定ができる。

### `<server></server>`
グローバル変数`$_SERVER`の設定ができる。 下記のコードだと`「$_SERVER[APP_ENV] = 'testing'」`という意味になる。

```php
<server name="APP_ENV" value="testing"/>
```

## おわりに
- Unitテストは単体のテスト、Featureテストは機能ごとのテスト。
- Controllerをテストしたい時はFeatureテスト。Controlle内のアクションメソッド内で使用されているメソッドの動作を確認するにはUnitテスト。
- テストが通る・通らないのパターンはどうすれば漏れなく全てのパターンが見つけられるのか疑問に感じたのでまた今度勉強してまとめようと思った。
- `src > config > database`に直で環境を書くよりも`.env.testing`を作成した方が管理しやすいのかな？と思った
- テストに使われているタグの意味が全然分からなかった、、、、もっと勉強する！

## 参考
https://readouble.com/laravel/5.8/ja/testing.html
https://phpunit.readthedocs.io/ja/latest/configuration.html
https://www.techpit.jp/courses/92