個人メモ。
環境
- Laravel 10.6.2
- PHP 8.2.0
- Vagrant CentOS7
準備
- PHPUnitの存在を確認しておきます。
Laravelルートで、下記のように出てくればOK。
$ vendor/bin/phpunit --version
PHPUnit 10.0.19 by Sebastian Bergmann and contributors.
動作確認。
laravelルートに移動して、デフォルトで置いてある
tests/Unit/ExampleTest.php
を動かしてみる。
$ vendor/bin/phpunit tests/Feature/ExampleTest.php
PHPUnit 10.0.19 by Sebastian Bergmann and contributors.
Runtime: PHP 8.2.0
Configuration: E:\vagrant\Vagrant2304\centos74\Laravelapp\laravelapp\phpunit.xml
. 1 / 1 (100%)
Time: 00:02.099, Memory: 24.00 MB
OK (1 test, 1 assertion)
動作OK。これは、これは、ルート/にアクセスして、存在あり:ステータス200を返すかどうかのテスト。
↓
\ExampleTest.php の中身の一部
public function test_the_application_returns_a_successful_response(): void
{
$response = $this->get('/');
$response->assertStatus(200);
}
-
phpunit.xml
phpunit.xmlは、テストの環境設定ファイルで、デフォルトでは
./tests/Unit
./tests/Feature
フォルダのテストを行うようになっているが、今回は単独ファイル1つのみを指定してテストを行う予定なので、このファイルは修正しない。 -
使用するDBを複製し、テスト用DBを作成しておきます。
(データの削除、変更などを行うため、専用のテスト用DBをmigrateなどを使用して作成しておく) -
Laravelルートの.envファイルをコピーし、.env.testingファイルを作ります。これはテスト実行時の環境設定ファイルになります。
プロジェクトのルートに.env.testingファイルを作成することもできます。このファイルは、PHPUnitテストを実行するとき、または--env=testingオプションを指定してArtisanコマンドを実行するときに、.envファイルの代わりに使用されます。
.env.testingを、テスト環境で使うデータベース設定に書き換えます。phpunit実行時には、この.env.testingの設定が使われます。
DB_DATABASE=
DB_USERNAME=
DB_PASSWORD=
- ファクトリーの作成
テスト時にデータを追加するファクトリを作ります。
Userのダミーデータを作るfactoryはあらかじめあるので、今回はこれを使います。
\database\factories\UserFactory.php の中身は下記のようになっています。
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
'img' => 'noimage.jpg',
];
}
他のテーブルでもfactoryを使う場合には、php artisan make:factory
コマンドで作成しておきます。
(今回は詳細は略)
- テストファイル作成
php artisan make:test コマンドでテストファイルを作成。今回はTodoTestという名前で作成。
※デフォルトでは、テストはtests/Featureディレクトリへ配置され、今回の場合には \tests\Feature\TodoTest.php が作られます。
# php artisan make: test TodoTest
INFO Test [tests/Feature/TodoTest.php] created successfully.
- ページのステータス確認
では、作られたTodoTest.phpを編集して、assertStatus
を呼び出す簡単なテストを作ってみます。
assertStatus は、レスポンスに指定HTTPステータスコードがあることを確認するコマンドです。
参考:HTTPテスト 10.x Laravel
ここで
assertStatus(200)
は未ログイン状態でページが見えることを確認。
assertStatus(302)
は未ログイン状態ではページが入れないことを確認。
namespace Tests\Feature;
use Tests\TestCase;
use App\Models\User;
use App\Models\Todo;
use Illuminate\Support\Facades\Hash;
// ページのステータス確認
public function test_todo_status(): void
{
//ログインしなくても見れる確認
$response = $this->get('/todo');
$response->assertStatus(200);
$response = $this->get('/todo/signup');
$response->assertStatus(200);
$response = $this->get('/todo/login');
$response->assertStatus(200);
$response = $this->get('todo/mypage_resign_logout');
$response->assertStatus(200);
$response = $this->get('todo/forget_password');
$response->assertStatus(200);
//ログインしないと入れない状態である確認
$response = $this->get('/todo/logout');
$response->assertStatus(302);
$response = $this->get('/todo_detail');
$response->assertStatus(302);
$response = $this->get('/todo/new');
$response->assertStatus(302);
$response = $this->get('/todo/edit');
$response->assertStatus(302);
$response = $this->get('/todo/del');
$response->assertStatus(302);
$response = $this->get('/todo/mypage');
$response->assertStatus(302);
$response = $this->get('/todo/mypage_pass');
$response->assertStatus(302);
$response = $this->get('/todo/mypage_resign');
$response->assertStatus(302);
}
テストファイルを作成したら、実行は、php artisan test
コマンドに続けてファイル名を指定することで、テストが呼び出される。
# php artisan test tests/Feature/TodoTest.php
PASS Tests\Feature\TodoTest
✓ todo status 0.12s
Tests: 1 passed (13 assertions)
Duration: 0.21s
このようにテストが成功した。
万が一エラーが出た場合には、コードを修正していく。
続けてテストを記載していく。
- マイページが表示できるかのテスト
// マイページが表示できるか
public function test_todo_mypage_show(): void
{
// ユーザーを1人作成し、そのユーザーが マイページを開いて、ステータスが200(無事表示できた)ことを確認
$user = User::factory()->create();
$response = $this->actingAs($user)->get('/todo/mypage');
$response->assertStatus(200);
// テストデータ削除
User::where('id', $user->id)->delete();
}
User::factory()->create(); でユーザーを1人作成。
そのユーザーが、ログインが必要なマイページにアクセスできるかを、assertStatus(200)
でテスト。
今回、毎回最後に
User::where('id', $user->id)->delete();
で毎回該当のユーザーデータを削除している。
※テストファイル上部に
use RefreshDatabase;
と入れておくと、毎回データを削除してくれるらしいのだが、既存のデータもすべて消えるとのことで、今回は追加したデータのみ、その都度削除している。
参考:データベースにテストデータが保存されるのを避ける方法
- データ追加テスト
// todo追加
public function test_can_new_todo(): void
{
$user = User::factory()->create();
$response = $this->actingAs($user)->get('/todo/new');
$response->assertStatus(200);
$response = $this->actingAs($user)->post('/todo/new', [
'title' => 'テスト投稿',
'todo' => 'テスト投稿をします',
]);
$this->assertDatabaseHas('todo', [
'title' => 'テスト投稿',
'todo' => 'テスト投稿をします',
'user_id' => $user->id,
]);
// テストデータ削除
Todo::where('user_id', $user->id)->delete();
User::where('id', $user->id)->delete();
}
これは、User::factory()->create()
でユーザーを作成、
assertStatus(200)
でページが表示されることを確認。
$this->actingAs($user)->post
でtodoテーブル(ユーザーテーブル1に対し多のリレーション関係にある)にデータ追加、
$this->assertDatabaseHas
でtodoテーブルにデータ追加されているかの確認。
最後に、今回追加したテストデータ削除。
- データ編集テスト
// todo編集
public function test_can_edit_todo(): void
{
$user = User::factory()->create();
// 投稿を作成
$response = $this->actingAs($user)->post('/todo/new', [
'title' => 'テスト投稿',
'todo' => 'テスト投稿をします',
]);
// 投稿を変更
$todo = Todo::where('user_id', $user->id)->first();
$todo_id = $todo->id;
$response = $this->actingAs($user)->post('/todo/edit?id=' . $todo_id, [
'title' => 'テスト投稿 変更',
'todo' => 'テスト投稿を変更します',
]);
// 変更したデータが存在することを確認
$this->assertDatabaseHas('todo', [
'title' => 'テスト投稿 変更',
'todo' => 'テスト投稿を変更します',
'user_id'=> $user->id,
]);
// テストデータ削除
Todo::where('user_id', $user->id)->delete();
User::where('id', $user->id)->delete();
}
これは、User::factory()->create()
でユーザーを作成、
まずデータを追加後、追加したデータを変更。
$this->assertDatabaseHas
でtodoテーブルのデータが変更されているか確認。
最後に、今回追加・変更したテストデータ削除。
- データ削除
// todo削除
public function test_can_del_todo(): void
{
$user = User::factory()->create();
// 投稿を作成
$response = $this->actingAs($user)->post('/todo/new', [
'title' => 'テスト投稿',
'todo' => 'テスト投稿をします',
]);
// 投稿を削除
Todo::where('user_id', $user->id)->delete();
// 変更したデータが存在しないことを確認
$this->assertDatabaseMissing('todo', [
'title' => 'テスト投稿',
'todo' => 'テスト投稿をします',
'user_id'=> $user->id,
]);
// テストデータ削除
Todo::where('user_id', $user->id)->delete();
User::where('id', $user->id)->delete();
}
これは、User::factory()->create()
でユーザーを作成、
まずデータを追加後、追加したデータを削除。
$this->assertDatabaseMissing
でtodoテーブルに該当データが存在しないことを確認。
最後に、今回追加したテストデータ削除。
- ログアウト
// todoログアウト
public function test_todo_logout(): void
{
// 未ログイン状態でマイページにアクセスできない
$response = $this->get('/todo/mypage');
$response->assertStatus(302);
// ユーザーを1人作成し、そのユーザーがマイページを開いて、ステータスが200(無事表示できた)ことを確認
$user = User::factory()->create();
$response = $this->actingAs($user)->get('/todo/mypage');
$response->assertStatus(200);
// ユーザーが認証済み
$this->assertAuthenticatedAs($user);
// ログアウト後に再度マイページを表示して、表示されないことを確認
$response = $this->actingAs($user)->get('/todo/logout');
// ログインページにリダイレクト
$response->assertStatus(302);
$response->assertRedirect('/todo');
// ログアウト後に認証されていないことを確認
$this->assertGuest();
// テストデータ削除
User::where('id', $user->id)->delete();
}
これは、未ログイン状態でマイページにアクセスできないことを確認、User::factory()->create()
でユーザーを作成し、マイページを開いて表示できることを確認。
ユーザーが認証済であることをassertAuthenticatedAs
で確認。
次に、ログアウト後に再度マイページを表示して、表示されないことを確認。ログアウト後に認証されていないことをassertGuest
で確認。
最後に、テストデータ削除。
- マイページ、ユーザー情報変更
// マイページ ユーザー情報変更
public function test_todo_mypage_change(): void
{
// ユーザー作成
$user = User::factory()->create();
// 投稿を変更(name,email)
$user_name = $user->name;
$response = $this->actingAs($user)->post('/todo/mypage', [
'name' => $user_name . '★',
'email' => 'testuser@gmail.com',
]);
$response->assertStatus(200);
// 変更したデータが存在することを確認
$this->assertDatabaseHas('users', [
'id'=> $user->id,
'name'=> $user_name . '★',
'email' => 'testuser@gmail.com',
]);
// テストデータ削除
User::where('id', $user->id)->delete();
}
これは、ユーザーを作成し、ユーザーのnameを変更、その後変更したデータが存在することをassertDatabaseHas
で確認、その後テストデータ削除。
- パスワード変更
// パスワード変更
public function test_todo_password_edit(): void
{
// ユーザー作成
$user = User::factory()->create();
// 投稿を変更
$password = '12345678'; //変更後パス
$response = $this->actingAs($user)->post('/todo/mypage_pass', [
'current_password' => 'password', //factoryで生成するpass
'user_password' => $password,
'confirm_password' => $password,
]);
$response->assertStatus(200);
$response->assertSeeText('更新しました。');
// ユーザー情報を変更したのでrefresh()を使って値を更新する
$user->refresh();
// 変更したパスワードがユーザーのパスワードと一致しているか確認
$this->assertTrue(Hash::check($password, $user->password));
// テストデータ削除
User::where('id', $user->id)->delete();
}
これは、ユーザーを作成し、ユーザーのパスワードを変更。
その後、変更したパスワードが現在のユーザーのパスワードと一致しているか確認。
- パスワード変更 5文字以上でなければエラー
// パスワード変更 5文字以上でなければエラー
public function test_todo_password_edit_5char(): void
{
// ユーザー作成
$user = User::factory()->create();
// 投稿を変更
$password = '1111'; //変更後パス
$response = $this->actingAs($user)->post('/todo/mypage_pass', [
'current_password' => 'password', //factoryで生成するpass
'user_password' => $password,
'confirm_password' => $password,
]);
$response->assertSessionHasErrorsIn("新しいパスワードは、5文字以上で入力してください。");
// テストデータ削除
User::where('id', $user->id)->delete();
}
これは、ユーザー作成し、バリデーションが5文字以上でなければエラーのところ、4文字でパスワードを更新しようとします。
assertSessionHasErrorsIn
で求めるエラー文が含まれているか確認します。
- 最後に動作確認
すべてのテストを実行してみます。途中でエラーが起こったところもあるのですが、ソースを修正することで、テストがすべて通過するようになりました。
# php artisan test tests/Feature/TodoTest.php
PASS Tests\Feature\TodoTest
✓ todo status 1.36s
✓ todo mypage show 0.37s
✓ can new todo 0.30s
✓ can edit todo 0.21s
✓ can del todo 0.15s
✓ todo logout 0.19s
✓ todo mypage change 0.40s
✓ todo password edit 0.32s
✓ todo password edit 5char 0.16s
Tests: 9 passed (35 assertions)
Duration: 3.93s
参考
テスト: テストの準備 10.x Laravel
データベーステスト 10.x Laravel
HTTPテスト 10.x Laravel
LaravelでPHPUnitを使ってCRUD処理のテストを自動化①【投稿の作成と保存テスト】
LaravelでPHPUnitを使ってテストする手法
Laravelでログイン関係のテストをしてみる
LaravelでEmailとPassword変更についてのテストを書いてみた