データベースのテストをする際には、テスト用の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>
https://qiita.com/colorrabbit/items/f660a4b6a2575b75a0e7
コマンドから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
https://qiita.com/colorrabbit/items/f660a4b6a2575b75a0e7
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; } }
もっといい方法あるよって方は教えてください。