Laravel × Docker でテスト用のデータベースコンテナを使う


新しい記事を書きました!
Docker × Laravel テスト用のデータベースコンテナを構築する


Laravel2 Advent Calendar 2019 - Qiita の 16日目 の記事です。

Laravel環境構築

ucan-lab/docker-laravel-alpine を元にLaravel環境を作ります。

$ git clone [email protected]:ucan-lab/docker-laravel-alpine.git
$ cd docker-laravel-alpine
$ make create-project

データベースコンテナ構成

こちらの docker-compose.yml から抜粋です。

docker-coompose.yml
  db:
    image: mysql:8.0
    volumes:
      - db-store:/var/lib/mysql
      - ./logs:/var/log/mysql
      - ./docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
    environment:
      - MYSQL_DATABASE=${DB_NAME}
      - MYSQL_USER=${DB_USER}
      - MYSQL_PASSWORD=${DB_PASS}
      - MYSQL_ROOT_PASSWORD=${DB_PASS}
      - TZ=${TZ}
    ports:
      - ${DB_PORT}:3306

  db-testing:
    image: mysql:8.0
    volumes:
      - ./docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
    tmpfs:
      - /var/lib/mysql
      - /var/log/mysql
    environment:
      - MYSQL_DATABASE=${DB_NAME}
      - MYSQL_USER=${DB_USER}
      - MYSQL_PASSWORD=${DB_PASS}
      - MYSQL_ROOT_PASSWORD=${DB_PASS}
      - TZ=${TZ}
    ports:
      - ${DB_TESTING_PORT}:3306

db コンテナが通常の開発用DBコンテナ
db-testing コンテナがテスト用DBコンテナ

phpunit.xml

vendor/bin/phpunit を実行すると何も指定しない場合 phpunit.xml が読み込まれます。

phpunit.xml
    <php>
        <server name="APP_ENV" value="testing"/>
        <server name="BCRYPT_ROUNDS" value="4"/>
        <server name="CACHE_DRIVER" value="array"/>
        <server name="MAIL_DRIVER" value="array"/>
        <server name="QUEUE_CONNECTION" value="sync"/>
        <server name="SESSION_DRIVER" value="array"/>
    </php>

<server> タグを <env> タグに書き換えます。

phpunit.xml
    <php>
        <env name="APP_ENV" value="testing" force="true"/>
        <env name="BCRYPT_ROUNDS" value="4"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="MAIL_DRIVER" value="array"/>
        <env name="QUEUE_CONNECTION" value="sync"/>
        <env name="SESSION_DRIVER" value="array"/>
    </php>

APP_ENVdocker-compose.yml にて環境変数として定義していますので、
phpunit.xml で既存の環境変数の上書きが必要です。

phpunit.xmlenvタグやserverタグを設定すると次のようなPHPコードになるイメージです。

$_ENV['APP_ENV'] = 'testing'; // env タグ
$_SERVER['APP_ENV'] = 'testing'; // server タグ

Dockerを使ってるとココは結構ハマりどころかなと思います。

CreatesApplicationトレイトで一度だけマイグレーションを実行する

テストを書く際は TestCase を継承してテストを作ります。

TestCase クラスは CreatesApplication トレイトをインポートしてます。

この createApplication() メソッドは各テスト実行の際に必ず呼ばれるのでこのタイミングで初回のみテスト用データベースのマイグレーションを実行します。

tests/CreatesApplication.php
<?php declare(strict_types=1);

namespace Tests;

use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\Artisan;

trait CreatesApplication
{
    /**
     * @var bool
     */
    protected $isSetUpDatabase = false;

    /**
     * Creates the application.
     *
     * @return \Illuminate\Foundation\Application
     */
    public function createApplication()
    {
        $app = require __DIR__.'/../bootstrap/app.php';

        $app->make(Kernel::class)->bootstrap();

        $this->setUpDatabase();

        return $app;
    }

    /**
     * Run migration once
     */
    protected function setUpDatabase(): void
    {
        if ($this->isSetUpDatabase) {
            return;
        }

        Artisan::call('migrate:fresh');

        $this->isSetUpDatabase = true;
    }
}

テスト実行

$ make app
$ ./vendor/bin/phpunit

参考

関連記事