CodeIgniter4のフィーチャーテストでデータベースを使う
この記事は CodeIgniter Advent Calendar 2020 - Qiita の15日目です。まだ、空きがありますので、興味のある方は気軽に参加してください。
CodeIgniter4のフィーチャーテスト の続きです。
公式チュートリアルの news アプリ のフィーチャーテストを書いてみます。
このアプリはデータベースを使っているため、テスト用のデータベースの準備が必要になります。
テスト時のデータベース設定
PHPUnit でのテスト実行時には、CodeIgniter4 の環境は testing
になります。
app/Config/Database.php
また、データベース設定ファイルの $tests
が使われます。デフォルトでは、SQLite3 のメモリデータベースになっています。
このように、開発用、本番用データベースとテスト用のデータベースの種類を変えるためには、特定のデータベースに依存したコードが一切ないことが必要になります。まあ、あまり現実的ではないかも知れません。
app/Config/Database.php
...
/**
* This database connection is used when
* running PHPUnit database tests.
*
* @var array
*/
public $tests = [
'DSN' => '',
'hostname' => '127.0.0.1',
'username' => '',
'password' => '',
'database' => ':memory:',
'DBDriver' => 'SQLite3',
'DBPrefix' => 'db_', // Needed to ensure we're working correctly with prefixes live. DO NOT REMOVE FOR CI DEVS
'pConnect' => false,
'DBDebug' => (ENVIRONMENT !== 'production'),
'cacheOn' => false,
'cacheDir' => '',
'charset' => 'utf8',
'DBCollat' => 'utf8_general_ci',
'swapPre' => '',
'encrypt' => false,
'compress' => false,
'strictOn' => false,
'failover' => [],
'port' => 3306,
];
...
デフォルトでは、DBPrefix
が db_
になっています。
もし、CodeIgniter4 の Query Builder を経由せずに発行されるクエリがある場合は、開発用とテスト用のテーブル名を一致させるように DBPrefix
を変更してください。
(2020-12-18 追記) 必要条件の記述をより正確にしました。
--- 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.xml
また、phpunit.xml
(作成されていない場合は phpunit.xml.dist
)にて、PHPUnit 実行時の環境変数 database.tests.database
と database.tests.DBDriver
が設定されています。
<php>
<!-- Directory containing phpunit.xml -->
<const name="HOMEPATH" value="./"/>
<!-- Directory containing the Paths config file -->
<const name="CONFIGPATH" value="./app/Config/"/>
<!-- Directory containing the front controller (index.php) -->
<const name="PUBLICPATH" value="./public/"/>
<!-- Database configuration -->
<!-- <env name="database.tests.hostname" value="localhost"/> -->
<!-- <env name="database.tests.database" value="tests"/> -->
<!-- <env name="database.tests.username" value="tests_user"/> -->
<!-- <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"/>
</php>
CodeIgniter4 の設定は、設定ファイルよりも環境変数が優先(設定ファイルの値が環境変数の値で上書き)されます。
また、 phpunit 実行時には、.env
より phpunit.xml
が先に評価されますので、phpunit.xml
が最優先されることになります。
テーブル作成とデータ挿入
とりあえず、以下で作ったマイグレーションとシーダーを使うことにします。
以下のようにテストファイルとプロパティを設定します。
tests/feature/NewsTest.php
<?php
namespace Tests\Feature;
use CodeIgniter\Test\FeatureTestCase;
class NewsTest extends FeatureTestCase
{
protected $refresh = true;
protected $namespace = 'App';
protected $basePath = APPPATH . 'Database';
protected $seed = 'NewsSeeder';
}
マイグレーション設定
$refresh
と $namespace
はマイグレーションに関する設定です。
$refresh
を true
にすると毎回データベースがリフレッシュされます。つまり、PHPUnit の setUp()
メソッド実行時に、マイグレーション 0 まで戻して再度マイグレーションを実行します。
$namespace
はマイグレーションファイルの名前空間です。Database\Migrations
は含めません。指定しない場合は、tests/_support/Database/Migrations
以下を探します。
なお、個人的には、テスト実行時にデータベース構造が変わるわけではないので、毎回マイグレーションをやり直すのは無駄だと思っています。
シーダー設定
$basePath
と $seed
はシーダーに関する設定です。
$basePath
はシーダーファイルが配置されているパスを設定します。Seeds
ディレクトリは含めません。指定しない場合は、tests/_support/Database/Seeds
以下を探します。
$seed
は実行するシーダーファイル名を設定します。
実際には、開発用のシーダーとテスト用のシーダーは分けたほうがいいと思います。
テストコードの作成
テストコードを完成させましょう。
tests/feature/NewsTest.php
<?php
namespace Tests\Feature;
use CodeIgniter\Test\FeatureTestCase;
class NewsTest extends FeatureTestCase
{
protected $refresh = true;
protected $namespace = 'App';
protected $basePath = APPPATH . 'Database';
protected $seed = 'NewsSeeder';
public function testGetNews()
{
$result = $this->get('news');
$result->assertStatus(200);
$result->assertSee('<title>CodeIgniter Tutorial</title>');
$result->assertSee('Elvis was sighted at the Podunk internet cafe.');
}
}
$this->get('news')
は $this->call('get', 'news')
と同じ意味です。
データベースにシーダーのデータが挿入されれば、それが表示されるはずです。
テストの実行
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
. 1 / 1 (100%)
Time: 418 ms, Memory: 10.00 MB
OK (1 test, 3 assertions)
通りました。
CodeIgniter4のフィーチャーテストでモックを使う に続きます。
この記事は CodeIgniter Advent Calendar 2020 - Qiita の15日目です。まだ、空きがありますので、興味のある方は気軽に参加してください。
参考
Date: 2020/12/15