Go to list of users who liked
Share on X(Twitter)
Share on Facebook
More than 3 years have passed since last update.
【Laravel】PHPUnitの実行でDBを汚染しないためにできる簡単なこと
環境
OS: Windows 10
PHP: 8.1.2
Laravel Framework: 8.81.0
docker-compose: 1.29.2
PHPUnit: 9.5.10
MySQL: 8.0
Laravel Sailを使用して、Laravelプロジェクトを立ち上げています。
プロジェクトを立ち上げる部分は、こちらのドキュメントでご確認ください。
RefreshDatabase DBの状態に影響されずテストする
use RefreshDatabase;をしてあげると、
。
各テスト毎にDBをリフレッシュするため、まっさらな状態にしてくれるので、
DBの状態を確認するアサーションである
$this->assertDatabaseCount(...);$this->assertDatabaseHas(...);$this->assertDatabaseMissing(...);
あたりが扱いやすくなります。
そして、テストによって追加されてしまうデータも残らないので安心です。
では、実際に動作を見るためにテストを作成しましょう。
テストの作成
まずは、テストの作成のために以下のコマンドを叩きます。
$./vendor/bin/sail artisan make:test Model/UserTestそして、作成されたファイルを以下のように修正します。
<?phpnamespaceTests\Feature\Model;useApp\Models\User;useIlluminate\Foundation\Testing\RefreshDatabase;useTests\TestCase;classUserTestextendsTestCase{useRefreshDatabase;constTABLE_NAME='users';protectedfunctionsetUp():void{parent::setUp();}/** * @return int * @throws \Exception */privatefunctionfactory():int{// 1~9のランダムな数値を取得$count=random_int(min:1,max:9);// $countの数だけ、新規にUserを作成するUser::factory($count)->create();return$count;}/** * @test * @group Model * @group User * * @return void * @throws \Exception */publicfunction全件取得():void{$count=$this->factory();// usersテーブルに$countの数だけデータが挿入されているか$this->assertDatabaseCount(table:self::TABLE_NAME,count:$count);$result=User::all();// 全件取得できているか$this->assertCount(expectedCount:$count,haystack:$result);}}さて、テストが作成できましたので、
これを動作させてみましょう。
テストの実行
テストの実行のためには、以下のコマンドを叩きます。
$./vendor/bin/sailtest--group=Model今回のテストには$this->assertDatabaseCount(...);が含まれています。
もし、です。
試しに3回ほど実行してみましょう!
$./vendor/bin/sailtest--group=Model PASS Tests\Feature\Model\UserTest ✓ 全件取得 Tests: 1 passed Time: 0.33s$./vendor/bin/sailtest--group=Model PASS Tests\Feature\Model\UserTest ✓ 全件取得 Tests: 1 passed Time: 0.30s$./vendor/bin/sailtest--group=Model PASS Tests\Feature\Model\UserTest ✓ 全件取得 Tests: 1 passed Time: 0.29s問題なくPASSしていますね!
これでテストができることが分かります。
テスト後のDBの状態を確認
次にテストによって追加されてしまうデータが残っていないことを確認します。
確認方法は何でも良いのですが、今回はできる限り簡潔に画面に表示します。
以下の実装を行いましょう。
<?phpuseIlluminate\Support\Facades\Route;/*|--------------------------------------------------------------------------| Web Routes|--------------------------------------------------------------------------|| Here is where you can register web routes for your application. These| routes are loaded by the RouteServiceProvider within a group which| contains the "web" middleware group. Now create something great!|*/Route::get('/',function(){$users=\App\Models\User::all();dd($users);});あとは、http://localhost/に接続すれば・・・
出ました!!
#items: []ということは、何のデータも入っていないことなので、
これでことが分かりました。
本当に影響がないか確認
テストがデータに影響しないこともデータが残ってないことも分かりました。
では、
それを確認するためにダミーデータを入れてからテストを実行してみましょう。
ダミーデータの作成
まずは、ダミーデータを作成するためにシーダーを作成する必要がありますので、
シーダーを作成するために以下のコマンドを叩きます。
$./vendor/bin/sail artisan make:seeder UserSeederシーダーの作成ができたら、ダミーデータを作成するために実装しましょう。
以下の修正を加えればOKです。
<?phpnamespaceDatabase\Seeders;useApp\Models\User;useIlluminate\Database\Seeder;classUserSeederextendsSeeder{/** * Run the database seeds. * * @return void */publicfunctionrun(){User::factory(10)->create();}}<?phpnamespaceDatabase\Seeders;useIlluminate\Database\Seeder;classDatabaseSeederextendsSeeder{/** * Seed the application's database. * * @return void */publicfunctionrun(){$this->call([UserSeeder::class,]);}}これでダミーデータを作成する準備が整ったので、以下のコマンドを叩きましょう。
$./vendor/bin/sail artisan db:seed作成しているかどうか、http://localhost/に接続して確認してみます。
#items: array:10 [▶]となっているので作成できていますね。
結果は・・・
では、テストを実行してから確認してみましょう。
$./vendor/bin/sailtest--group=Modelそして、http://localhost/に接続・・・
き、消えてる・・・。
ということで、汚染しない代わりにのです。
解決方法
テスト実行の度にダミーデータを挿入するのも手間がかかりますし、
手動で追加したデータなどは消えてしまいます。
これでは、根本的な解決になりません。
根本的な解決方法を考えるなら
すればよいのです。
sqliteを使用する
設定は何もこだわらなければ、とても簡単です。
以下のように、コメントアウトを外すだけです。
<?xml version="1.0" encoding="UTF-8"?><phpunitxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"bootstrap="vendor/autoload.php"colors="true"><testsuites><testsuitename="Unit"><directorysuffix="Test.php">./tests/Unit</directory></testsuite><testsuitename="Feature"><directorysuffix="Test.php">./tests/Feature</directory></testsuite></testsuites><coverageprocessUncoveredFiles="true"><include><directorysuffix=".php">./app</directory></include></coverage><php><servername="APP_ENV"value="testing"/><servername="BCRYPT_ROUNDS"value="4"/><servername="CACHE_DRIVER"value="array"/><servername="DB_CONNECTION"value="sqlite"/><servername="DB_DATABASE"value=":memory:"/><servername="MAIL_MAILER"value="array"/><servername="QUEUE_CONNECTION"value="sync"/><servername="SESSION_DRIVER"value="array"/><servername="TELESCOPE_ENABLED"value="false"/></php></phpunit>これで設定完了です。
テスト実行(sqlite)
先程と同じようにダミーデータの作成し、テストを実行してみます。
$./vendor/bin/sail artisan db:seed$./vendor/bin/sailtest--group=Modelそして、http://localhost/に接続・・・
やりました!
ダミーデータが残ったままです!
テストで違うDB環境を使用する
簡単な設定でしたが、残念ながら
そんなときは、大人しく別のDBを用意する方法が良いでしょう。
.env.testing
まず、.env.testingを作成します。
一番楽なのは、.envを複製してリネームすることです。
重要なのは、APP_KEYにキーがあること、DB_HOSTが.envと異なることです。
今回は、DB_HOSTをmysql.testとします。
...APP_KEY=(キーが入っている)...DB_CONNECTION=mysqlDB_HOST=mysql.testDB_PORT=(.envと一緒)DB_DATABASE=(.envと一緒)DB_USERNAME=(.envと一緒)DB_PASSWORD=(.envと一緒)...APP_KEYにキーが入っていない
その場合は、以下のコマンドで生成しましょう。
$./vendor/bin/sail artisan key:generate--env=testingdocker-compose.yml
先程、.env.testingで追加したDB_HOSTを追加します。
今回はmysql.testですね。
mysql.test:image:'mysql/mysql-server:8.0'environment:MYSQL_ROOT_PASSWORD:'${DB_PASSWORD}'MYSQL_ROOT_HOST:"%"MYSQL_DATABASE:'${DB_DATABASE}'MYSQL_USER:'${DB_USERNAME}'MYSQL_PASSWORD:'${DB_PASSWORD}'MYSQL_ALLOW_EMPTY_PASSWORD:1networks:-sailテスト用に使用するだけなので、
追加した後は、sailを再度立ち上げましょう!
$./vendor/bin/sail up-dテスト実行(別DB)
テストを実行してみます。
$./vendor/bin/sail artisan db:seed$./vendor/bin/sailtest--group=Modelそして、http://localhost/に接続・・・
こちらでも問題なく残っていますね!
まとめ
ということで、上記の手順によりDBの汚染を防ぐことができます。
テストを記述するのはとても大切だと思っているので、
備忘録ではありますが、この記事があなたの役に立てば嬉しいです。
Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme





