Laravel

【Laravel】Dockerを使って開発環境でテストを実行する

【Laravel】Dockerを使って開発環境でテストを実行する

今回はLaravelアプリ開発時に、テスト用のデータベースをDockerで準備してテストを実行する方法を解説します。

 

前提として、Dockerを使ってLaravelの環境構築はできている(localhostでアクセスしたらLaravelのwelcomeページが見えている)ものとします。

 

まだここまで出来ていない方は、以前に解説した記事を貼っておくのでこれを参考に環境を構築しておいて下さい。

DockerでLaravelの環境構築をする手順をまとめてみた【Nginx】
DockerでLaravelの環境構築をする手順をまとめてみた【Nginx】DockerでLaravelの環境構築をする手順をまとめてみました(Nginx)。参考になれば幸いです。...

【Laravel】Dockerを使って開発環境でテストを実行する

ここまでで、nginx(別にapceheとかでもいいいです)、php、db(MySQL)コンテナを立ち上げて、Laravelの画面(welcomeページ)をブラウザに表示させるところまでは出来ているはずです。

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 ps

上記のコマンドでうまくコンテナが立ち上がらない場合は、以前に立ち上げたコンテナのキャッシュが邪魔をしている可能性が考えられます。以下のコマンドを順に打つことで、キャッシュを含めずにコンテナを立ち上げ直すことができるので試してみて下さい。

docker-compose down

 

docker-compose build --no-cache

 

docker-compose up -d

 

補足記事:【Docker】キャッシュを含めずにbuildしてコンテナを立ち上げ直す

 

 

以上でテスト用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ディレクトリ配下のファイル構成も以下のように修正しました。コントローラテストを行うためのディレクトリを生成するイメージです。

 

変更前

変更前のディレクトリ構造

 

変更後

変更後のディレクトリ構造

参考:Laravelアプリで開発テスト-超準備編-

 

ここまで出来たら、後はテストを書いて実行するだけです。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

 

以下のような状態になったら接続完了です。

mysqlに接続

 

ここで以下のコマンドを打って、データベースの一覧を表示させます。

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でテストを実行したいと思っている方の参考になっていれば幸いです。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA