0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Laravel】例外・バリデーション・メール送信のテストコードをPHPUnitで書く

Last updated at Posted at 2023-11-07

はじめに

久しぶりに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()
    • メール送信されたことをチェックします。

まとめ

例外・バリデーション・メール送信をピックアップしてテストコードの一部をまとめました。

実務で今まであまりテストコードを書いてなかったので、よく使うものがあればまた紹介したいと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?