データベースのテストをする際には、テスト用のDBを用意して、そのDBでテストした方が良い。
理由
テストDBを用意して、テストを実行する際、
DatabaseMigrations
やDatabaseTransactions
を使ってもDBに全く影響を与えないわけでは無いです。
AUTO_INCREMENTの値など、一部は影響を受けてしまいます
Laravel 5.4 で手軽にテストを書こう! | 株式会社インフィニットループ技術ブログ
実際に試してみました。
-
use DatabaseTransactions;
が無い状態で、AUTO_INCREMENTのカラムがあるレコードを追加するコードのあるテストを実行(※以降テスト) -
use DatabaseTransactions;
がある状態テストを実行 -
use DatabaseTransactions;
が無い状態テストを実行
そうするとAUTO_INCREMENTのカラムが連番にリませんでした。
テストをすることで少しでも本番DBなどに影響を与えてしまうのは良くないので、テストする時用でDBを切り替えてた方が良いと思いました。
テストDBでのテスト方法
テスト用のDBを作成する。
hoge_testing
※surfixに _testingをつけるとテストDBだということが分かりやすい。
envファイルでDBを切り替えるパターン
開発環境、本番環境、ローカル環境などでテストDB名が違う場合は、このパターンを使うのが良いと思う。
テスト用のenvファイルを作る
ファイル名
.env.testing
DB名の箇所だけ書き換える
DB_DATABASE=hoge_testing
テストDBに対してmigrateを実行する方法
php artisan migrate --seed --env=testing
--env=testingをつけることで.env.testingのenvファイルを読んでmigrateを実行する事ができる。
Laravel5 で別環境(APP_ENV)で artisan コマンドを実行 - Qiita
テストコード内でmigrate:refresh
などを実行しているのであれば、コマンドでのmigrateの実行は不要かと思います。
phpunit.xmlでDBを切り替えるパターン
phpunit.xmlファイル内に<env name="DB_DATABASE" value="hoge_testing"/>
を追加。
追加する箇所は以下の通りです。
<php>
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
<env name="DB_DATABASE" value="hoge_testing"/>
</php>
[Laravel 5.2] Laravelでtest用DBにmigrateする方法 - Qiita
コマンドからmigrateを実行する場合
config/database.phpのmysqlの設定コピーして、databaseの箇所だけテストDBのDB名に書き換える。
'mysql_testing' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => 'hoge_testing',
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'modes' => [
],
'engine' => null,
],
後は以下のコマンドを実行すればテストDBに対してmigrate:refresh
を実行することが出来る。
php artisan migrate:refresh --database=mysql_testing
[Laravel 5.2] Laravelでtest用DBにmigrateする方法 - Qiita
config をクリアする。
php artisan config:clear
このコマンドを実行せずにArtisan::call('migrate:refresh');
など実行があるテストを実行したりすると、本番DBのデータが飛んだりするので要注意です。
DBの初期状態でデータベースのテストをする場合
テストクラスに以下メソッドを追加。
public function setUp() {
parent::setUp();
Artisan::call('migrate:refresh');
Artisan::call('db:seed');
}
migrate:refresh
を実行する際はmigrationファイルのdownメソッドにupメソッドが行った操作を元戻す処理 を書いておく必要があります。
https://readouble.com/laravel/5.3/ja/migrations.html
外部キー制約がある場合
以下のエラーが出る時があります。
SQLSTATE[23000]: Integrity constraint violation: 1217 Cannot delete or update a parent row: a foreign key constraint fails
以下の様にして一時的に外部キー制約を解除する。
public function down()
{
Schema::disableForeignKeyConstraints();
Schema::dropIfExists('user');
Schema::enableForeignKeyConstraints();
}
Laravel5でテスト時にtesting設定を使う方法 - アルファブレンド プログラミングチップス
laravelのバージョンが5.5であればRefreshDatabase;
が使える。
use RefreshDatabase;
を追加することで
テスト前にMigrationとSeederが実行される。
LaravelでHTTPテスト - Qiita
テストを実行
'phpunit'をコマンドで実行
おまけ
setUpBeforeClass以外の方法でクラスで一回だけ実行するメソッドを作る方法
migrate:refresh
やdb:seed
を、setUpメソッドに記述すると、テストにかかる時間が結構長くなってしまうので、クラスで一回だけ実行すれば場合はsetUpBeforeClassというメソッド内で実行すると良いようです。しかしsetUpBeforeClass内でenv()
やlogger()
などのlaravelで用意してくれているhelperは使えませんでした。
以下の様な処理がしたかったがenvが呼べない。
public static function setUpBeforeClass()
{
if(env('DB_DATABASE_TESTING') == 'hoge_testing'){
Artisan::call('migrate:refresh');
Artisan::call('db:seed');
self::insertTestData();
}
}
なのでsetUpメソッドを一回のみ実行するようにしました。
private static $isSetup = false;
public function setUp()
{
parent::setUp();
if(env('DB_DATABASE_TESTING') == 'hoge_testing' && self::$isSetup === false){
Artisan::call('migrate:refresh');
Artisan::call('db:seed');
self::$isSetup = true;
}
}
もっといい方法あるよって方は教えてください。