CodeIgniter4でテストDBをMySQLにする

この記事は CodeIgniter Advent Calendar 2020 - Qiita の19日目です。まだ、空きがありますので、興味のある方は気軽に参加してください。

CodeIgniter4のフィーチャーテストでモックを使う の続きです。

テスト用のデータベースはデフォルトの SQLite3 のメモリデータベースを使っていましたが、それを開発環境に合わせて MySQL に変更します。

テスト用データベースの作成

テスト用のデータベースを作成します。

$ mysql -uroot -p

テスト用データベース ci4tutorial_test を作成します。

CREATE DATABASE ci4tutorial_test DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

アプリ用のデータベースユーザ dbuser に権限を与えます。

GRANT ALL PRIVILEGES ON ci4tutorial_test.* TO dbuser@localhost;

データベース接続設定

テストデータベースに接続するための設定が必要です。

環境固有の設定と考え、.env で設定することにします。

phpunit.xml

phpunit.xml での環境変数の設定を削除(コメントアウト)します。

--- a/phpunit.xml
+++ b/phpunit.xml
@@ -52,7 +52,7 @@
 <!--   <env name="database.tests.password" value=""/>               -->
 <!--   <env name="database.tests.DBDriver" value="MySQLi"/>     -->
 <!--   <env name="database.tests.DBPrefix" value="tests_"/>     -->
-           <env name="database.tests.database" value=":memory:"/>
-           <env name="database.tests.DBDriver" value="SQLite3"/>
+<!-- <env name="database.tests.database" value=":memory:"/>   -->
+<!-- <env name="database.tests.DBDriver" value="SQLite3"/>    -->
        </php>
 </phpunit>

.env

.env に以下の設定を追加します。

database.tests.hostname = localhost
database.tests.database = ci4tutorial_test
database.tests.username = dbuser
database.tests.password = dbpassword
database.tests.DBDriver = MySQLi

app/Config/Database.php

テーブル名のプリフィックスは必要ないので、空文字に変更します。

これで、開発用とテスト用のテーブル名が同一になります。

--- a/app/Config/Database.php
+++ b/app/Config/Database.php
@@ -64,7 +64,7 @@ class Database extends \CodeIgniter\Database\Config
                'password' => '',
                'database' => ':memory:',
                'DBDriver' => 'SQLite3',
-               'DBPrefix' => 'db_',  // Needed to ensure we're working correctly with prefixes live. DO NOT REMOVE FOR CI DEVS
+               'DBPrefix' => '',
                'pConnect' => false,
                'DBDebug'  => (ENVIRONMENT !== 'production'),
                'cacheOn'  => false,

テストの実行

phpunit を実行します。

$ vendor/bin/phpunit tests/feature/NewsTest.php
PHPUnit 8.5.13 by Sebastian Bergmann and contributors.

Error:         XDEBUG_MODE=coverage or xdebug.mode=coverage has to be set

..                                                                  2 / 2 (100%)

Time: 459 ms, Memory: 12.00 MB

OK (2 tests, 7 assertions)

通りました。

データベース内のデータの確認

MySQL に接続して中身のデータを確認しておきます。

mysql> use ci4tutorial_test;
mysql> select * from news \G
*************************** 1. row ***************************
   id: 1
title: Elvis sighted
 slug: elvis-sighted
 body: Elvis was sighted at the Podunk internet cafe. It looked like he was writing a CodeIgniter app.
*************************** 2. row ***************************
   id: 2
title: Say it isn't so!
 slug: say-it-isnt-so
 body: Scientists conclude that some programmers have a sense of humor.
*************************** 3. row ***************************
   id: 3
title: Caffeination, Yes!
 slug: caffeination-yes
 body: World's largest coffee shop open onsite nested coffee shop for staff only.
3 rows in set (0.01 sec)

ci4tutorial_test.news テーブルにデータが挿入されています。

データベースのリフレッシュをやめる

テストメソッドごとにデータベースをリフレッシュするのは重いのでやめてみます。

(2021-02-23 追記) CodeIgniter 4.0.5以降にはマイグレーションを実行しない設定やマイグレーションやシーダーを一度だけ実行する設定が追加されました。

ます、テスト用の NewsSeeder を以下のように作成します。

tests/_support/Database/Seeds/NewsSeeder.php

<?php

namespace Tests\Support\Database\Seeds;

use CodeIgniter\Database\Seeder;

class NewsSeeder extends Seeder
{
    public function run()
    {
        $table = 'news';

        $this->db->table($table)->truncate();

        $data = [
            [
                'title' => 'Elvis sighted',
                'slug' => 'elvis-sighted',
                'body' => 'Elvis was sighted at the Podunk internet cafe. It looked like he was writing a CodeIgniter app.',
            ],
        ];
        $this->db->table($table)->insertBatch($data);
    }
}

テストコードを変更します。

--- a/tests/feature/NewsTest.php
+++ b/tests/feature/NewsTest.php
@@ -3,16 +3,16 @@
 namespace Tests\Feature;

 use App\Models\NewsModel;
+use Tests\Support\Database\Seeds\NewsSeeder;
 use CodeIgniter\Database\ModelFactory;
 use CodeIgniter\Test\FeatureTestCase;

 class NewsTest extends FeatureTestCase
 {
-    protected $refresh = true;
+    protected $refresh = false;
     protected $namespace = 'App';

-    protected $basePath = APPPATH . 'Database';
-    protected $seed = 'NewsSeeder';
+    protected $seed = NewsSeeder::class;

     public function testGetNews()
     {

$refresh は false に設定しても migration は setUp() 内で実行されます(Pull Request #3221 参照)。

$basePath を削除すればデフォルトの tests/_support/Database/Seeds/ 以下を探すようになります。

これで、毎回リフレッシュすることはなくなりました。

この記事は CodeIgniter Advent Calendar 2020 - Qiita の19日目です。まだ、空きがありますので、興味のある方は気軽に参加してください。

参考

Date: 2020/12/19

Tags: codeigniter, codeigniter4, database, testing