前回話したログインのスロットル機能。もちろん手動、つまりブラウザ、で確認はできます。しかし、手動ではいちいち面倒ですね。自動で動作を確認できたらもっと良いです。そこで登場するのがユニットテスト。難しくはないです。チェックしたいのは、

  1. パスワードが正しいときのログインが成功するかのテスト
  2. パスワードを間違えて、失敗回数がデフォルトの5回となったときに、スロットされるかのテスト
  3. その後デフォルトの60秒待って、パスワードが正しいときに成功するかのテスト

他にもいくつか考えられますが、最低限は以上としてテストを作成してみましょう。

注意:パスワードには理解しやすいように日本語としていますが、実際は英数字が一般的です。

class LoginTest extends TestCase
{
    public function testLoginSuccess()
    {
        $this->visit('/auth/login')
            ->type('test@gmail.com', 'email')
            ->type('正しいパスワード', 'password')
            ->press('保存')
            ->see('ホームページ');
    }

    public function testLoginThrottle()
    {
        for($i=1;$i <=5; $i++)
        {
            $this->visit('/auth/login')
                ->type('test@gmail.com', 'email')
                ->type('間違ったパスワード', 'password')
                ->press('ログイン')
                ->see('Eメールとパスワードにマッチするレコードがありません。');
        }

        $this->visit('/auth/login')
            ->type('test@gmail.com', 'email')
            ->type('間違ったパスワード', 'password')
            ->press('ログイン')
            ->see('ログインの失敗回数が設定を超えました。次回のログインまで60秒お待ちください。');

        sleep(10);

        $this->visit('/auth/login')
            ->type('test@gmail.com', 'email')
            ->type('正しいパスワード', 'password')
            ->press('ログイン')
            ->see('ログインの失敗回数が設定を超えました。');

        sleep(50);

        $this->visit('/auth/login')
            ->type('test@gmail.com', 'email')
            ->type('正しいパスワード', 'password')
            ->press('ログイン')
            ->see('ホームページ');
    }
}

最初のテスト、testLoginSuccessは、正しいパスワードを入力したときのテストで、その後「ホームページ」という文が入ったページへ行くとする仮定。

次のtestLoginThrottleは、スロットルされるまでの失敗回数の確認とスロットル解除の確認のテスト。まず間違ったパスワードを入れて5回失敗させます。画面には、「Eメールとパスワードにマッチするレコードがありません」のエラーメッセージが表示されます。その後、さらに失敗すると、今度はログインをスロットルしたメッセージが表示されます。ここから60秒経過しないと次のログインができません。確認のために10秒後に正しいパスワードでログインしてみましょう。そこでは、さらに「ログインの失敗回数が設定を超えました。」を含むエラーメッセージがでます。残りの秒数は誤差が出ると思うので、その部分の確認はしません。そして、50秒後(つまり、スロットル開始から60秒後)には、正しいパスワードでログインが成功となるはずです。

さて、ここで注意です。Laravelに含まれるphpunitのテストの設定ファイルは、以下の内容です。

<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         bootstrap="bootstrap/autoload.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false">
    <testsuites>
        <testsuite name="Application Test Suite">
            <directory>./tests/</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist>
            <directory suffix=".php">app/</directory>
        </whitelist>
    </filter>
    <php>
        <env name="APP_ENV" value="testing"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
    </php>
</phpunit>

前回話したように、ログイン失敗回数や現在スロットルされていることなどの情報は、デフォルトではファイルを使用して行っています。しかし、テストでは CACHE_DRIVERは配列設定となっています。私のテストでは、そのためか上のテストはスロットル期間終了後に成功とはなりませんでした。どうも残りの秒数のカウントが負となっていしまい、うまくいかない。

この設定をphpunit.xmlでarrayからfileあるいはdatabaseに変更とすると、うまく行きました。

By khino