Laravel 5.4で導入されたLaravel Duskをテスト後にDBリセットさせるようにして試してみた

# はじめに
Laravel 5.4で導入されたブラウザテストのためのLaravel Duskを使ってみました。
[※公式ドキュメント](https://laravel.com/docs/5.4/dusk)
Laravel Duskは、簡単なコマンドでテストコードを用意できたり、
テストがこけた時にスクリーンショットを撮ってくれたり、色々と便利です。
今回は、Laravel自体はすでに導入済みということを想定して、Laravel Duskを導入する手順からまとめました。

# 環境
- OS X El Capitan 10.11.6
- PHP 7.0.18
- laravel/framework 5.4.19
- laravel/dusk 1.1.0
- MySQL 5.7.18

# Laravel Duskの導入
公式ドキュメントの方法に沿って、composerを使って導入しました。
下記コマンドで `composer.json` に自動で追記してくれ、Laravel Duskの導入までやってくれます。

```
$ composer require laravel/dusk
```
# Laravel Duskを使用するための準備
## Laravel Duskインストール
artisanコマンドでインストールします。

```
$ php artisan dusk:install
```
インストールが成功すると、 `/tests` 配下に以下のファイルが作成されます。

```
/tests/Browser/ExampleTest.php
/tests/Browser/Pages/HomePage.php
/tests/Browser/Pages/Page.php
/tests/Browser/console/.gitignore
/tests/Browser/screenshots/.gitignore
/tests/DuskTestCase.php
```

`/tests/Browser/ExampleTest.php` は、デフォルトで作成されるLaravelのTOP画面のテストです。
テストでは、TOP画面（/）にアクセスし、「Laravel」という文字があることを確認している簡単なテストです。

```/tests/Browser/ExampleTest.php
<?php

namespace Tests\Browser;

use Tests\DuskTestCase;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;

class ExampleTest extends DuskTestCase
{
    /**
     * A basic browser test example.
     *
     * @return void
     */
    public function testBasicExample()
    {
        $this->browse(function (Browser $browser) {
            $browser->visit('/')
                    ->assertSee('Laravel');
        });
    }
}
```

## 標準の認証機能の導入
今回は、ログイン画面でのブラウザテストをしたいので、Laravelが標準で用意している認証機能を入れます。
これで基本的な認証機能が使えるようになります。
※すでに認証機能を入れている場合、この手順は不要です。

```
$ php artisan make:auth
```

## ログイン画面のテストコード作成
下記artisanコマンドでテストコードを作成してくれます。

```
$ php artisan dusk:make LoginTest
```
以下のテストコードが作成されます。

```/tests/Browser/LoginTest.php
<?php
namespace Tests\Browser;
use App\User;
use Tests\DuskTestCase;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;
class LoginTest extends DuskTestCase
{
    /**
     * A Dusk test example.
     *
     * @return void
     */
    public function testExample()
    {
        $user = factory(User::class)->create([
            'email' => 'taylor@laravel.com',
        ]);
        $this->browse(function ($browser) use ($user) {
            $browser->visit('/login')
                    ->type('email', $user->email)
                    ->type('password', 'secret')
                    ->press('Login')
                    ->assertPathIs('/home');
        });
    }
}
```
`factory(User::class)->create ` でテスト用のユーザを作成し、ログイン後に、 ホーム画面(/home)に遷移していることを確認するテストです。
ただ、このままだとテスト用に作成したデータがDB上に残ったままになります。
テストを何度も実行することを考えると不便なので、テスト後にデータベースをリセットするように以下のようにコードを修正します。

```/tests/Browser/LoginTest.php
<?php
namespace Tests\Browser;
use App\User;
use Tests\DuskTestCase;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;
class LoginTest extends DuskTestCase
{
    use DatabaseMigrations;

    /**
     * A Dusk test example.
     *
     * @return void
     */
    public function testExample()
    {
        $user = factory(User::class)->create([
            'email' => 'taylor@laravel.com',
        ]);
        $this->browse(function ($browser) use ($user) {
            $browser->visit('/login')
                    ->type('email', $user->email)
                    ->type('password', 'secret')
                    ->press('Login')
                    ->assertPathIs('/home');
        });
    }
}
```
上記のように `use DatabaseMigrations;` を追加するだけです。
これにより、テストの毎にマイグレーションを実行し、テストが終了した後には、DBをリセットしてくれます。
なので、あらかじめテスト用のDBを作成しておくだけで十分です。

## 環境ファイルの準備
テスト実行時は、 `.env` に記載されている情報を元にテストが実行されますが、
テスト用に内容を書き換える必要がある場合、その都度書き換えるのがめんどいので、テスト用の環境ファイルを用意します。
名称は、 `.env.dusk.local` とします。
`local` の部分が環境になり、今回はlocal環境のためこの名称としています。

```.env.dusk.local（一部抜粋）
APP_URL=http://localhost
```
APP_URLは、実際にブラウザで画面にアクセスするときのURLと同じ値を設定します。

# テスト実行
いよいよテストを実行します。
以下のようにしてテストを実行することができます。

```
$ php artisan dusk

PHPUnit 5.7.19 by Sebastian Bergmann and contributors.

..                                                                  2 / 2 (100%)

Time: 22.77 seconds, Memory: 14.00MB

OK (2 tests, 2 assertions)
```
こちらは正常終了した場合の結果です。
せっかくなので、失敗した時にどうなるか見てみます。

```/tests/Browser/LoginTest.php
<?php
namespace Tests\Browser;
use App\User;
use Tests\DuskTestCase;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;
class LoginTest extends DuskTestCase
{
    use DatabaseMigrations;

    /**
     * A Dusk test example.
     *
     * @return void
     */
    public function testExample()
    {
        $user = factory(User::class)->create([
            'email' => 'taylor@laravel.com',
        ]);
        $this->browse(function ($browser) use ($user) {
            $browser->visit('/login')
                    ->type('email', $user->email)
                    ->type('password', 'secret')
                    ->press('Login')
                    ->assertPathIs('/home')
                    ->assertSee('あいうえお');
        });
    }
}
```
`assertSee('あいうえお')` を追加しました。
これは、ホーム画面で「あいうえお」という文字列が存在するかを確認するためのメソッドです。
この状態で実行してみます。

```
$ php artisan dusk

PHPUnit 5.7.19 by Sebastian Bergmann and contributors.

.F                                                                  2 / 2 (100%)

Time: 21.74 seconds, Memory: 14.00MB

There was 1 failure:

1) Tests\Browser\LoginTest::testExample
Did not see expected text [あいうえお] within element [body].
Failed asserting that false is true.

/vendor/laravel/dusk/src/Concerns/MakesAssertions.php:239
/vendor/laravel/dusk/src/Concerns/MakesAssertions.php:210
/tests/Browser/LoginTest.php:34
/vendor/laravel/dusk/src/TestCase.php:91
/tests/Browser/LoginTest.php:35

FAILURES!
Tests: 2, Assertions: 3, Failures: 1.
```
テストが失敗しました。
`Did not see expected text [あいうえお] within element [body].` と出ています。
ホーム画面に「あいうえお」という文字列はありませんよということですね。
次にスクリーンショットを見てみます。
`/tests/Browser/screenshots/failure-testExample-0.png` のように、
`/tests/Browser/screenshots`以下にエラー時のスクリーンショットが作成されます。

![スクリーンショット 2017-05-13 21.23.18.png](https://qiita-image-store.s3.amazonaws.com/0/122482/461354fd-d4ce-c429-54d7-ca4e09a99ee6.png)
実際にログインした後のホーム画面のスクリーンショットです。
スクリーンショットを見ると、確かに「あいうえお」という文字列が無いことが分かります。

# まとめ
今回は、Laravel Duskの特徴を簡単に紹介させていただきました。
他にもLaravelには便利な機能がいっぱいあるので、時間を見つけて記事を書いてみたいと思います。