はじめに
久しぶりにPHPの案件をやることになり、
テストコードについて調べる機会が増えたので、よく使うものを列挙します!
コードサンプル
sample.php
/**
* {@inheritdoc}
*/
public function setup(): void
{
parent::setup();
$this->user = User::factory()->create(
[
'email' => 'test@gmail.com',
'first_name' => 'テスト',
'last_name' => '太郎',
]
);
$this->app->bind(CognitoServiceInterface::class, fn ($_) => new MockCognitoService());
}
/**
* @test
*/
public function メールアドレス更新処理で例外が発生する()
{
$response = $this->get(route('sample.index'));
$response->assertRedirect(route('auth.login'));
$this->actingAs($this->user);
$this->instance(
SampleService::class,
Mockery::mock(SampleService::class, function ($mock) {
$mock->shouldReceive('updateEmail')->once()->andThrow(RuntimeException::class);
}),
);
$response = $this->put(route('sample.update_email', ['email' => self::UPDATE_EMAIL]));
$response->assertRedirect(route('sample.index'));
$response->assertSessionHas(
'error',
fn ($message) => $message == __('messages.error.unexpected'),
);
}
/**
* @test
*/
public function メールアドレス更新処理がバリデーションエラーになる()
{
$response = $this->get(route('sample.index'));
$response->assertRedirect(route('auth.login'));
$this->actingAs($this->user);
$params = $this->getUpdateParams();
Arr::set($params, 'email', '');
$response = $this
->from(route('sample.edit'))
->put(route('sample.update', $params));
$this->assertDatabaseMissing('users', $params);
$response->assertInvalid(['email' => 'メールアドレスは必須です。']);
$response->assertRedirect(route('sample.edit'));
}
/**
* @test
*/
public function メールアドレス変更確認メール送信に失敗する()
{
Mail::fake();
$this->mock(SampleService::class, function (MockInterface $mock) {
$mock->shouldReceive('sendEmail')->once()->andThrow(InternalErrorException::class);
});
/** @var SampleService $service */
$service = app(SampleService::class);
$this->assertThrows(
fn () => $service->sendEmail(
self::UPDATE_EMAIL,
$this->user
),
InternalErrorException::class,
);
Mail::assertNotSent(UpdateMail::class);
}
前処理
setup() で処理をするようにしています。
ここではテストコードに必要な処理を記載しています。
共通
common.php
$response = $this->get(route('sample.index'));
$response->assertRedirect(route('auth.login'));
$this->actingAs($this->user);
assertRedirect はログイン画面にリダイレクトし、
actingAs でテストケース内で、ログイン状態が維持するようにしています。
例外(Exception)のテスト
exception.php
$this->instance(
SampleService::class,
Mockery::mock(SampleService::class, function ($mock) {
$mock->shouldReceive('updateEmail')->once()->andThrow(RuntimeException::class);
}),
);
ここでは、Mockery を使って例外を発生させています。
具体的には、SampleServiceで定義されている「updateEmail」でRuntimeExceptionを発生させています。
try {
//
} catch (RuntimeException $e) {
throw new Exception('エラー');
} catch (Exception $e) {
throw $e;
}
Controller や Service などで上記のような try catch をする箇所がおそらく発生すると思うのですが、ここを想定したテストになります。
バリデーションのテスト
validation.php
$this->assertDatabaseMissing('users', $params);
$response->assertInvalid(['email' => 'メールアドレスは必須です。']);
$response->assertRedirect(route('sample.edit'));
-
assertDatabaseMissing
- usersテーブルに $paramsのデータが登録されていないかチェックします。
-
assertInvalid
- 想定されるバリデーションエラーメッセージをチェックします。
-
assertRedirect
- バリデーションエラー発生時のリダイレクト先をチェックします。
メール送信のテスト
email.php
Mail::fake();
...
Mail::assertNotSent(UpdateMail::class);
- Mail::fake()
- 実際にはメールを送らないように設定します。
- Mail::assertNotSent()
- メール送信されたことをチェックします。
まとめ
例外・バリデーション・メール送信をピックアップしてテストコードの一部をまとめました。
実務で今まであまりテストコードを書いてなかったので、よく使うものがあればまた紹介したいと思います。