Laravel6でテストコードを書いてみよう

Laravelでは、PHPUnitが標準で組み込まれています。
なのでセットアップ完了後からすぐにテストコードを書き始めることができます！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/838372/f18b5058-3042-b0da-8f67-5fff809aaf0d.png)

**「何故テストコードを書かないといけないのか」**に関しては、他の方の記事が素晴らしいのでこちらを見ていただければと思います。

https://qiita.com/halkt/items/930097f76f5d82f9079b

https://qiita.com/ryosukes/items/b8e1b855c2ce33471675

## `Feature`と`Unit`の使い分け
`tests`配下に、`Feature`と`Unit`のディレクトリがあります。

`Feature`にはControllerやRouting、Middlewareなどの機能テストを実装します。
それ以外の単体テストを`Unit`で実装します。

## テストの作成

```terminal:ターミナル
// Featureディレクトリにテストを作成する
$ php artisan make:test UserTest

// Unitディレクトリにテストを作成する
$ php artisan make:test UserTest --unit
```

## テストの実行

```terminal:ターミナル
// Featureディレクトリのテストを実行する
$ vendor/bin/phpunit tests/Feature/UserTest

// Utilディレクトリのテストを実行する
$ vendor/bin/phpunit tests/Util/UserTest

// 全体をテストするときは以下でもOK
$ php artisan test
```

## ケーススタディ
### ①ビューのテスト
`$response = $this->get('/')`で、'/'にアクセスした結果のレスポンスを取得できます。

そして、`$response->assertStatus(200)`で、そのレスポンスが問題ないこと(ステータスが200 OKであること)をチェックしています。

`assertViewIs("welcome")`で、`welcome`というビューが表示されるかどうかをチェックします。

```php:tests/Feature/RouteTest.php
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class RouteTest extends TestCase
{
  public function testRouteTop()
  {
    $response = $this->get("/");
    $response->assertStatus(200)->assertViewIs("welcome");
  }
}
```

### ②ログイン状況のテスト
以下は未ログインユーザーのテストです。
`$response->assertRedirect("/login");`でリダイレクトされ、`/login`に移動します。

```php:tests/Feature/RouteTest.php
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class RouteTest extends TestCase
{
  public function testGuestCreate()
  {
    $response = $this->get("/create");

    $response->assertRedirect("/login");
  }
}
```

以下はログインユーザーのテストです。
`actingAs($user)`でログインします。

```php:tests/Feature/RouteTest.php
<?php

namespace Tests\Feature;

// models
use App\Models\User;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class RouteTest extends TestCase
{
  use RefreshDatabase;

  public function testAuthCreate()
  {
    // Userモデルを準備
    $user = factory(User::class)->create();

    // ログインして投稿画面へアクセスすることを実行
    $response = $this->actingAs($user)->get("/create");

    // レスポンスを検証
    $response->assertStatus(200)->assertViewIs("/create");
  }
}
```

テストのコードの書き方のパターンに「AAA」というのがあります。
Arrage-Act-Assert、日本語でいうと準備・実行・検証となります。

http://wiki.c2.com/?ArrangeActAssert



## よく使うアサートなどをまとめます。
### 【assertStatus】レスポンスのステータスが指定したものと正しいか
```php:
$response->assertStatus(200);
```

### 【assertViewIs】指定したビューが返る
```php
$response->assertViewIs("welcome");
```

### 【assertRedirect】指定したURIへリダイレクト
```php
$response->assertRedirect("/login");
```

### 【actingAs】ログインする
```php
$response = $this->actingAs($user)
```

## トレイトに関して
コードを再利用するための仕組みをトレイトといいます。
トレイトは、継承と似たPHPの機能です。
汎用性の高いメソッドなどをトレイトとしてまとめておき、他の複数のクラスで共通して使う、という使い方をします。

https://www.php.net/manual/ja/language.oop5.traits.php

### 【RefreshDatabase】データベースに対して行ったアクションをすべて白紙にする
```php:tests/Feature/RouteTest.php
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class RouteTest extends TestCase
{
  use RefreshDatabase;

  public function testRouteTop()
  {
    $response = $this->get("/");
    $response->assertStatus(200)->assertViewIs("welcome");
  }
}
```