Memo

メモ > 技術 > フレームワーク: Laravel6 > テスト

テスト
■概要 テストの方針は案件ごとに決めておく 今回の方針は ・コントローラからはサービスを呼び出す(リポジトリやモデルを直接呼び出さない) ・サービスの各メソッドに対してテストを書く ・データベースアクセスなしでテストできるように、Mockeryでリポジトリのモックを作る ・HTTPリクエストで各ページの参照をテスト とする ■テストの実行方法 テスト: テストの準備 6.x Laravel https://readouble.com/laravel/6.x/ja/testing.html
$ sudo su -s /bin/bash - nginx $ cd /var/www/main $ ./vendor/bin/phpunit PHPUnit 8.5.2 by Sebastian Bergmann and contributors. .. 2 / 2 (100%) Time: 5.47 seconds, Memory: 20.00 MB OK (2 tests, 2 assertions)
デフォルトでは、以下にあるテストが実行される tests\Unit\ExampleTest.php tests\Feature\ExampleTest.php UnitとFeatureの違いは、公式サイトでは以下のように紹介されている Unit: ユニットテストは極小さい、コードの独立した一部をテストします。 実際、ほとんどのユニット(Unit)テストは一つのメソッドに焦点をあてます。 Feature: 機能テストは、多くのオブジェクトがそれぞれどのように関しているかとか、 JSONエンドポイントへ完全なHTTPリクエストを送ることさえ含む、コードの幅広い範囲をテストします。 以下はユニットテストの例 (以下ははじめから作成されているテスト。値の一致をテストする) tests\Unit\ExampleTest.php
<?php namespace Tests\Unit; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; class ExampleTest extends TestCase { /** * A basic test example. * * @return void */ public function testBasicTest() { $this->assertTrue(true); } }
以下は機能テストの例 (以下ははじめから作成されているテスト。トップページへのHTTPリクエストをテストする) tests\Feature\ExampleTest.php
<?php namespace Tests\Feature; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; class ExampleTest extends TestCase { /** * A basic test example. * * @return void */ public function testBasicTest() { $response = $this->get('/'); $response->assertStatus(200); } }
■テストの作成方法
$ php artisan make:test UserServiceTest --unit Test created successfully.
「--unit」を付けるとUnitディレクトリにテストの雛形が作成され、 付けなければFeatureディレクトリにテストの雛形が作成される 作成された雛形をもとに、独自のテストを作成するといい テスト: テストの準備 7.x Laravel https://readouble.com/laravel/7.x/ja/testing.html 以降で、UserServiceのテストを作成していく ■ダミーデータの作成 テスト時にダミーデータが必要な場合、Fakerを使うことでデータを作成してくれる まずは、Fakerが作成するダミーデータを日本語にする config\app.php
'faker_locale' => 'en_US', ↓ 'faker_locale' => 'ja_JP',
以下でFactoryを作成できる ただし UserFactory ははじめから作成済になっている
$ php artisan make:Factory UserFactory
内容は以下のとおり。ダミーのユーザデータを作成してくれる ただし今回のプログラムに合わせて、「use App\User;」を「use App\Models\User;」に変更している database\factories\UserFactory.php
<?php /** @var \Illuminate\Database\Eloquent\Factory $factory */ use App\Models\User; use Faker\Generator as Faker; use Illuminate\Support\Str; /* |-------------------------------------------------------------------------- | Model Factories |-------------------------------------------------------------------------- | | This directory should contain each of the model factory definitions for | your application. Factories provide a convenient way to generate new | model instances for testing / seeding your application's database. | */ $factory->define(User::class, function (Faker $faker) { return [ 'name' => $faker->name, 'email' => $faker->unique()->safeEmail, 'email_verified_at' => now(), 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 'remember_token' => Str::random(10), ]; });
[Laravel5.1]Fakerチートシート - Qiita https://qiita.com/tosite0345/items/1d47961947a6770053af ■テストの編集 先の手順において
$ php artisan make:test UserServiceTest --unit
で作成したテストを元に作り込むものとする PHPUnit\Framework\TestCase (PHPUnitのクラス)を Tests\TestCase (Laravelのクラス)に差し替えることにより、 Laravelのファサードなどが使えるようになる Laravelで "A facade root has not been set." というエラーが出た場合の対処法 - Qiita https://qiita.com/aminevsky/items/784573234d071c769288 Fakerで作成したデータを各メソッドで使い回す場合など、 共通の初期処理が必要なら setup() で行う PHPUnitのsetUp()を使ったら「must be compatible」とエラーが表示される - Qiita https://qiita.com/stoneBK7/items/fcc898f38ee161b38ef4 tests\Unit\UserServiceTest.php
<?php namespace Tests\Unit; //use Illuminate\Foundation\Testing\RefreshDatabase; //use PHPUnit\Framework\TestCase; use Tests\TestCase; class UserServiceTest extends TestCase { private $users; /** * Setup the test environment. * * @return void */ protected function setUp(): void { parent::setUp(); // ダミーデータを作成 $this->users = factory(\App\Models\User::class, 3)->make(); /* foreach ($this->users as $user) { echo '[' . $user->name . ']'; echo '[' . $user->email . ']'; } */ } /** * Clean up the testing environment before the next test. * * @return void */ protected function tearDown(): void { parent::tearDown(); // ダミーデータを削除 $this->users = null; } /** * 1件取得 * * @return void */ public function testGetUser() { // 1件取得 $user = $this->users; // リポジトリのモックを作成 $userRepositoryMock = \Mockery::mock(\App\Repositories\UserRepository::class); $userRepositoryMock->shouldReceive('find')->andReturn($user); // リポジトリをモックに差し替えてサービスを作成 $userService = new \App\Services\UserService( $userRepositoryMock ); $this->assertEquals($user, $userService->getUser(1)); } /** * 検索して取得 * * @return void */ public function testGetUsers() { // リポジトリのモックを作成 $userRepositoryMock = \Mockery::mock(\App\Repositories\UserRepository::class); $userRepositoryMock->shouldReceive('search')->andReturn($this->users); // リポジトリをモックに差し替えてサービスを作成 $userService = new \App\Services\UserService( $userRepositoryMock ); $this->assertEquals($this->users, $userService->getUsers()); } /** * 件数を取得 * * @return void */ public function testCountUsers() { // リポジトリのモックを作成 $userRepositoryMock = \Mockery::mock(\App\Repositories\UserRepository::class); $userRepositoryMock->shouldReceive('count')->andReturn(count($this->users)); // リポジトリをモックに差し替えてサービスを作成 $userService = new \App\Services\UserService( $userRepositoryMock ); $this->assertEquals(3, $userService->countUsers()); } /** * 登録 * * @return void */ public function testStoreUser() { // リポジトリのモックを作成 $userRepositoryMock = \Mockery::mock(\App\Repositories\UserRepository::class); $userRepositoryMock->shouldReceive('save')->andReturn(new \App\Models\User); // リポジトリをモックに差し替えてサービスを作成 $userService = new \App\Services\UserService( $userRepositoryMock ); $postRequest = new \App\Http\Requests\StoreUserRequest(); $postRequest->merge([ 'name' => 'Taro Yamada', 'email' => 'taro@example.com', 'password' => 'abcd1234', ]); $this->assertInstanceOf('\App\Models\User', $userService->storeUser($postRequest)); } /** * 編集 * * @return void */ public function testUpdateUser() { // リポジトリのモックを作成 $userRepositoryMock = \Mockery::mock(\App\Repositories\UserRepository::class); $userRepositoryMock->shouldReceive('save')->andReturn(new \App\Models\User); // リポジトリをモックに差し替えてサービスを作成 $userService = new \App\Services\UserService( $userRepositoryMock ); $postRequest = new \App\Http\Requests\StoreUserRequest(); $postRequest->merge([ 'name' => 'Taro Yamada', 'email' => 'taro@example.com', 'password' => 'abcd1234', ]); $this->assertInstanceOf('\App\Models\User', $userService->storeUser($postRequest, 1)); } /** * 削除 * * @return void */ public function testDeleteUser() { // リポジトリのモックを作成 $userRepositoryMock = \Mockery::mock(\App\Repositories\UserRepository::class); $userRepositoryMock->shouldReceive('delete')->andReturn(new \App\Models\User); // リポジトリをモックに差し替えてサービスを作成 $userService = new \App\Services\UserService( $userRepositoryMock ); $this->assertInstanceOf('\App\Models\User', $userService->deleteUser(1)); } }
プログラム内の以下の部分で、ダミーデータを作成している factory(\App\Models\User::class, 3)->make(); 以下のように make() ではなく create() を使うと、実際にデータベースにも登録される factory(\App\Models\User::class, 3)->create();

Advertisement