今回はLaravelアプリ開発時に、テスト用のデータベースをDockerで準備してテストを実行する方法を解説します。
前提として、Dockerを使ってLaravelの環境構築はできている(localhostでアクセスしたらLaravelのwelcomeページが見えている)ものとします。
まだここまで出来ていない方は、以前に解説した記事を貼っておくのでこれを参考に環境を構築しておいて下さい。
【Laravel】Dockerを使って開発環境でテストを実行する
ここまでで、nginx(別にapceheとかでもいいいです)、php、db(MySQL)コンテナを立ち上げて、Laravelの画面(welcomeページ)をブラウザに表示させるところまでは出来ているはずです。
ハッキリ言ってここまでのことができていれば、テスト用のDBコンテナを増やすのは簡単です。
なぜなら、単に同じようなDB(MySQL)コンテナをもう一つ立ち上げればいいだけだからです。docker-composeにサクッと追記するだけで終わります。
ただ、実際にLaravelからDBに接続してテストを実行するためには、多少の設定を加える必要があります。
今回はその部分を重点的に解説していきます。
DBコンテナを増やす(docker-composeに追記)
まずはdocker-compose.ymlに設定を追加してDBコンテナを増やしましょう。以下のようにdb-testコンテナ用の設定を追記して下さい(一番最後のdb-testの部分です)。
version: '3' services: app: container_name: app build: ./docker/php volumes: - .:/var/www nginx: image: nginx container_name: nginx ports: - 8000:80 volumes: - .:/var/www - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf working_dir: /var/www depends_on: - app db: image: mysql:5.7 container_name: db environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: database MYSQL_USER: db-user MYSQL_PASSWORD: db-pass TZ: 'Asia/Tokyo' command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci volumes: - ./docker/db/data:/var/lib/mysql - ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf - ./docker/db/sql:/docker-entrypoint-initdb.d ports: - 3306:3306 db-test: image: mysql:5.7 container_name: db-test environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: database MYSQL_USER: db-user MYSQL_PASSWORD: db-pass TZ: 'Asia/Tokyo' command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci volumes: - ./docker/db-test/data:/var/lib/mysql - ./docker/db-test/my.cnf:/etc/mysql/conf.d/my.cnf - ./docker/db-test/sql:/docker-entrypoint-initdb.d ports: - 3000:3306
ポイントは以下の3つです。
- container_nameの名前をdbコンテナとは別にする(同じ名前のコンテナを立ち上げることはできない)
- volumesでマウントするローカルファイルのパスをdbコンテナとは別にする
- ポート番号をdbコンテナと同じにしない(同じマシン内で同じポート番号を指定することはできない)
volumesに関しては、テストデータを永続化する必要性はほとんど無いと思うので、別に書かなくてもいいかなとは思います。
以上で新しくテスト用のdbコンテナを立ち上げるための作業は終了です。
さっそくコンテナを立ち上げてみましょう。以下のコマンドを打って下さい。
docker-compose up -d --build
docker-compose ps
でコンテナの状態を確認してUpになっていたらOKです。db-testコンテナは立ち上がっています。
上記のコマンドでうまくコンテナが立ち上がらない場合は、以前に立ち上げたコンテナのキャッシュが邪魔をしている可能性が考えられます。以下のコマンドを順に打つことで、キャッシュを含めずにコンテナを立ち上げ直すことができるので試してみて下さい。
docker-compose down
docker-compose build --no-cache
docker-compose up -d
以上でテスト用dbコンテナの準備は完了です。
Laravel側でテスト用DBとの接続情報を設定する
次に、Laravel側でテスト用dbコンテナとの接続情報を指定します。
.envファイルにはすでにアプリ用dbコンテナとの接続情報が書かれてあるため、新たに.env.testingを生成して、その中にテスト用dbコンテナとの接続情報を記述することにしましょう。
.env.testingに以下の項目を記述して下さい。(docker-compose.ymlで指定した値です)
APP_ENV=testing APP_KEY= DB_CONNECTION=mysql DB_HOST=db-test DB_PORT=3306 DB_DATABASE=database DB_USERNAME=db-user DB_PASSWORD=db-pass
APP_KEYが設定されていないことに気付くと思います。
これはLaravelアプリ内で暗号化やパスワードリセットといった用途に使われているkeyです。これをセットしていなかったらテスト実行時にエラーが出るので注意しましょう。
新たなAPP_KEYを.env.testingにセットするには以下のコマンドを実行します。これを実行することで、APP_KEYに自動的にkeyをセットしてくれます。
※最後にオプションとして–env=testingを付けることで、.envではなく、.env.testingを参照してくれます。
php artisan key:generate --env=testing
参考:【Laravel】.env.testingの使用方法と注意点
APP_KEYについてより詳しく知りたい方は、こちらの記事を参考にしてみて下さい。APP_KEYの用途について分かりやすくまとめられています。
以上でLaravel側からテスト用dbに接続するための設定は完了です。
あとは、マイグレーション等でphp artisan migrate
の代わりに、オプション付きで php artisan migrate --env=testing
のように記述することで、.envではなく、.env.testingを参照してテスト用のテーブルを生成してくれます。(このコマンドは後ほど実行します)
詳しくは公式に書かれてあるので参考にして下さい。
テスト用ファイルを用意してテストを記述する
「テスト用dbコンテナの生成」と「.env.testingにテスト用dbへの接続情報を記載」が完了しました。
すぐにでもテストを実行したいところですが、あと少し設定しなくてはならない項目があります。
まずは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="Test"> <directory suffix="Test.php">./tests</directory> </testsuite> </testsuites> <filter> <whitelist processUncoveredFilesFromWhitelist="true"> <directory suffix=".php">./app</directory> </whitelist> </filter> <php> <server name="APP_ENV" value="testing"/> </php> </phpunit>
大まかに言うと、以下の2点を修正しました。
- <php>内の無駄な記述を削除
- testsuiteのdirectoryを、testsディレクトリ配下のテストを実行するように修正
特に重要なのは、 <server name="APP_ENV" value="testing"/>
の部分です。これがあることによって、テスト実行時に.env.testingを参照してくれます。(これがなかったら.envを参照してしまう)
また、これらの変更に合わせて、testsディレクトリ配下のファイル構成も以下のように修正しました。コントローラテストを行うためのディレクトリを生成するイメージです。
変更前
変更後
ここまで出来たら、後はテストを書いて実行するだけです。ExampleTest.phpに以下の内容を記述して下さい。
<?php namespace Tests\Http\Controllers; use Illuminate\Foundation\Testing\DatabaseMigrations; use Tests\TestCase; use App\User; class ExampleTest extends TestCase { use DatabaseMigrations; /** @test */ public function 簡単な画面のテスト() { $response = $this->get('/'); $response->assertStatus(200); } /** @test */ public function 簡単なデータベース接続のテスト() { // テスト用ユーザーの生成 User::create([ 'name' => 'testTaro', 'email' => 'example777@mail.com', 'password' => "testPass" ]); // 作成したユーザーがdbにあるかチェック $this->assertDatabaseHas('users', [ 'name' => 'testTaro', 'email' => 'example777@mail.com', 'password' => "testPass" ]); } }
画面が表示されるか(HTTPステータスコードとして200が返ってくるか)および作成したユーザーをdbに格納できるかをチェックする簡易的なテストです。
テーブルを準備してテストを実行する
テスト前の最後の準備として、マイグレーションを行ってテスト用db内にusersテーブルを作成します。
※usersのマイグレーションファイルはデフォルトで用意されているので、特別準備の必要はありません。
アプリのコンテナ内で以下のコマンドを実行して下さい。
php artisan migrate --env=testing
※アプリのコンテナに入るコマンドは docker-compose exec app bash
です。
このコマンドにより、マイグレーションの際に.envではなく.env.testingを参照してくれるため、テスト用のdbコンテナ内にテーブルを生成することができます。
マイグレーションが実行されます。
マイグレーションが終わったら、テスト用db内にテーブルが作成されているかを確認しましょう。
まずはテスト用dbコンテナの中に入ります。
docker-compose exec db-test bash
コンテナ内に入ったら、MySQLに接続するために、以下のコマンドを打ちます。
mysql -u root -p
するとパスワードの入力が求められるはずなので、rootと入力して下さい(docker-compose.ymlで指定した値です)
ちなみに、パスワードも同じタイミングで入力したい場合は、以下のように-pに続けて入力して下さい。
mysql -u root -proot
以下のような状態になったら接続完了です。
ここで以下のコマンドを打って、データベースの一覧を表示させます。
show databases;
すると、docker-composeで定義したデータベース(database)も含まれていることが確認できます。
次に、このdatabaseを選択して中身のテーブル構造を確認します。まずは以下のコマンドを打って下さい。
use database;
データベースが選択できたので、中身のテーブル構造を確認しましょう。
これでusersテーブルが生成されていれば、Laravelとの接続はうまくいっていることになります。
以下のコマンドを打って下さい。
show tables;
usersテーブルの存在が確認できました。テスト用dbとの接続はうまくいってそうです。
さて、後はテストを実行するだけです。
アプリのコンテナに入った後に、以下のコマンドを実行して下さい。(Laravelでテストを実行するコマンドです)
※今回のようにテストファイルの数が少ない場合は、 vendor/bin/phpunit
だけでも大丈夫です。
vendor/bin/phpunit tests/Http/Controllers/ExampleTest.php
結果はこちら。
二つとも成功しています。
よって、Laravelの画面が正しく表示されていることと、テスト用dbコンテナと正しく疎通できていることが確認できました。
おわりに
今回はLaravelを用いたアプリ開発時にDockerを使ってテスト用のデータベースを用意し、テストを実行する方法を解説しました。
少しでもこれからDockerを使ってLaravelでテストを実行したいと思っている方の参考になっていれば幸いです。