読者です 読者をやめる 読者になる 読者になる

tanaka's Programming Memo

プログラミングについてのメモ。

Laravel5.3 テストでテスト専用のデータベースを使う

(submitFormでは、フォームを指定すべきなのがわかりづらい例になっていたので修正 2016/11/1)

Laravelアプリの開発時に、テストする時とそうでない時で、別のデータベースを使うようにする方法です。これをやっておけば、テスト時に好き勝手にデータベースをいじれるので便利です。

PHP 用のテストフレームワークである Codeception を導入すると、テスト時に使用する環境設定ファイルを指定できるので、そこでデータベースの情報を変更できます。 Codeception は Laravel を始めとする様々なフレームワークに対応していて導入しやすく、テスト用の機能も充実しているので導入して損はありません。

Laravel5.3でプロジェクトを作成して、 Codeception を組み込んで、データベースのテストを行うまでの簡単な流れです。

前提

  • macOS Sierra 10.12
  • PHP 5.6.19
  • MySQL 5.7.16
  • Laravel 5.3
  • Componser 1.2.1

以上はインストール済みとします。


Laravelプロジェクトと Codeception の設定

  • ターミナルを起動して、プロジェクトを作成するフォルダーを開く
  • 以下で、プロジェクトを作成。プロジェクト名は適宜変更のこと
laravel new lara53-codeception
cd lara53-codeception
  • 続けて、 Codeception を組み込む
composer require codeception/codeception --dev

Codeceptionのセットアップ

以下を実行することで、Codeception のセットアップができます。

composer exec codecept bootstrap

これにより、 tests ディレクトリーと設定ファイル[codeception.yml]が作成されます。加えて、Acceptanceテスト(実際のWebブラウザーを使ったテスト), Functionalテスト(実際のWebブラウザーは使わない機能テスト), Unitテスト(単体テスト) の3つのスイート(suites)用の設定ファイルも作成されます。

この時点で、以下でテストが動きます。

composer exec codecept run

まだテスト内容がないので、「No tests executed!」と表示されます。


データベースを準備

MySQLを起動していなかったら、新しいターミナルを開いて、以下で起動します。

sudo mysqld_safe

Laravelプロジェクトのフォルダーにいるターミナルで、以下でテスト用のデータベースを2つ作成します。

  • 以下で、MySQLに接続
mysql -u root -p
  • パスワードを入力
  • 以下で、テスト用と、通常用のデータベースの2つを作成
create database lara53_codeception;
create database lara53_codeception_test;
  • それぞれのアクセス用のユーザーを作成
create user
    'lara53_code'@'localhost' identified by 'YourPassword1',
    'lara53_code_test'@'localhost' identified by 'YourPassword2';
  • それぞれのデータベースにアクセス権を設定
GRANT ALL ON lara53_codeception.* TO 'lara53_code'@'localhost';
GRANT ALL ON lara53_codeception_test.* TO 'lara53_code_test'@'localhost';

設定を作成

テスト用の環境ファイルを用意するために、以下で .env を複製します。

cp .env .env.testing

.env.testing のデータベース設定をテスト専用のものにしておけば、テスト時はテスト専用に作ったデータベース上でテストができるので、テストと他の作業のデータを切り離すことができます。

  • .gitignore を開いて、 .env.testing を追加する
  • .env をエディターで開いて、通常の利用データベースへの接続を設定する。以下、このページの例に沿った内容。適宜、自分の環境の値に変更のこと
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=lara53_codeception
DB_USERNAME=lara53_code
DB_PASSWORD=YourPassword1
  • 上書き保存する
  • .env.testing をエディターで開いて、通常の利用データベースへの接続を設定する。以下、このページの例に沿った内容。適宜、自分の環境の値に変更のこと
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=lara53_codeception_test
DB_USERNAME=lara53_code_test
DB_PASSWORD=YourPassword2
  • APP_ENV を testing にしておく
  • 上書き保存

データベースを作成

簡単に動作を試すために、ログイン機能を実装して、それでテストをしてみましょう。以下で、ユーザー登録できるようにします。

php artisan make:auth

http://localhost:8000/ をリロードしたり、開くと、右上に LOGIN と REGISTER のリンクが表示されます。続いて、以下でデータベースを作成します。

php artisan migrate

以上でできるのは、 .env で定義されたデータベースに対してです。以下で、登録状況を表示してみましょう。

mysql -u root -p
<rootのパスワードを入力>
use lara53_codeception;
show tables;

以上で、[migrations][password_resets][users]の3つのテーブルが作成されていることが確認できます。念のため、テスト用のデータベースにはまだテーブルが登録されていないことを確認しましょう。

use lara53_codeception_test;
show tables;

こちらはまだ作成していないので、「Empty set」と表示されます。 exit で mysql から抜けます。


通常のユーザーを登録しておく

  • http://localhost:8000 を開いたら、[REGISTER]を押す
  • 項目を入力して、ユーザーを登録する。メールアドレスは仮のもので良い

テスト用の設定を作成

Codeception で Laravel5 のテストが動くように設定をします。Codeception には以下のようなテスト方法があります。

  • Webブラウザーの動作を模して機能のテストを行う Functionalテスト
  • Seleniumを使って実際にWebブラウザー上で機能のテストを行う Acceptance テスト
  • PHPの関数ベースで単体テストを行う Unit テスト
  • ステータスレスのWebAPIのテストを行う API テスト
  • などなど

ここでは、 Functional テストで、テスト用のデータベースへのユーザー登録を試します。

Functionalテストの設定

Laravel5 - Codeception - Documentation を参考に設定を作成します。

  • tests/functional.suite.yml をエディターで開く
  • 以下のように設定する
class_name: FunctionalTester
modules:
    enabled:
        - Laravel5:
            environment_file: .env.testing
            run_database_migrations: true
        - \Helper\Functional
  • 上書き保存する

テストを作成する

04-FunctionalTests - Codeception - Documentation を参考にテストを作成します。

  • ターミナルから、以下を実行
composer exec codecept g:cest functional User
  • tests/functional/UserCest.php ができるので、エディターで開く(Cestとは、 Codeception のテスト用のファイルのこと)
  • tryToTest()メソッドに、以下のコードを追加
    public function tryToTest(FunctionalTester $I)
    {
        // ユーザー数が0であることを確認する
        \PHPUnit_Framework_Assert::assertEquals(0, App\User::all()->count());

        // ユーザー登録ページを表示
        $I->amOnPage('/register');
        // 必要な情報を設定して、ユーザー登録フォームのsubmitを押す(2016/11/1に変更)
        $I->submitForm('#registerUserForm', [
            'name' => 'TestUser',
            'email' => 'test@test.com',
            'password' => 'testtest',
            'password_confirmation' => 'testtest'
        ]);
        // ユーザーの登録に成功したら、以下のメッセージが表示される
        $I->see('You are logged in!');

        // ユーザー数が増えて1になっていることを確認する
        \PHPUnit_Framework_Assert::assertEquals(1, App\User::all()->count());
    }

submitFormで登録フォームを指定できるようにIDを追加します。

  • resources/views/auth/register.blade.php をエディターで開く
  • <form から始まる行を探して、以下のようにID属性を追加する
                    <form id="registerUserForm" class="form-horizontal" role="form" method="POST" action="{{ url('/register') }}">

以上で、テスト用のデータベースにユーザーを登録したことが確認できます。

通常のデータベースに変更がないことを確認する

通常のデータベースの中身を確認して、テストによる影響を受けていないことを確認します。ターミナルで以下を入力します。

mysql -u root -p
<ルートパスワードを入力>
use lara53_codeception;
select * from users;

データに変更がないことが確認できるはずです。


まとめ

以上で、 Laravel5.3 で Codeception を使ったテストが動くようになりました。Functionalテストで使える関数は以下で調べてください。

また、PHPUnitにあるアサーションは、 \PHPUnit_Framework_Assert::assertTrue(true); のようにすれば利用できます。PHPUnitアサーションは以下で調べてください。