Laravel 11.4 で導入された Exceptions facade を試す
まえがき
Laravel 11.4 で追加されたテスト用の Exceptions facade を試してみました。
今まで普通に使っていた expectException
とは何が違うのか、軽く比較しながら見て行きたいと思います。
Laravel 日本語ドキュメント(例外処理)
ドキュメント:PHPUnit Expecting Exceptions
本題
Exceptions facade で追加されたテスト用メソッドは幾つかありますが、今回はもっとも基本の assertReported
を使って見ます。なお、ここではあくまで HTTP テスト($this->get() とかするやつ)で見て行きます。
まずは、こんなコントローラ(web.php)があったとします。
Route::get('/', function () {
throw new RuntimeException('例外が発生しましたよ');
return view('welcome');
});
現実世界では、より具体的な例外クラスを投げたりしますが、その辺は今回は気にせず、上記に対するテストを今までの書き方で、PHPUnit で書いてみると、
use RuntimeException;
public function test_例外が発生(): void
{
$this->withoutExceptionHandling();
$this->expectException(RuntimeException::class);
$this->get('/');
}
こんな感じかと思います。HTTP テストなので、withoutExceptionHandling
でエラーハンドリングを抑えつつ、PHPUnit の expectException
を使って例外の発生テストを書いていました。
では、新しく追加された Exceptions facade を使うとどんな風に書けるかと言うと、
use Illuminate\Support\Facades\Exceptions;
use RuntimeException;
public function test_assertReport(): void
{
Exceptions::fake();
$this->get('/');
Exceptions::assertReported(RuntimeException::class);
}
おぉ!何となく良くなったような、そうでもないような…。少なくとも withoutExceptionHandling
は不要になったものの、代わりに Exceptions::fake();
を書く必要がありますね。
しかしよくよく見てみますと、メソッド名は、assertThrows
ではなく、assertReported
となっています。実は $this->assertThrows
というメソッドは Ver.9.12 からあったりする訳ですが、何故、assertReported
よ?と思ったりします。という事で、試しに発生する例外クラスを RuntimeException
ではなく、Laravel 内部の ModelNotFoundException
とした場合、、、
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
throw new ModelNotFoundException('例外が発生しましたよ');
return view('welcome');
});
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Exceptions;
// 従来タイプ
public function test_例外が発生(): void
{
$this->withoutExceptionHandling();
$this->expectException(ModelNotFoundException::class);
$this->get('/');
}
// 新タイプ
public function test_assertReport(): void
{
Exceptions::fake();
$this->get('/');
Exceptions::assertReported(ModelNotFoundException::class);
}
従来タイプは普通にテストにパスしますが、新タイプは、普通にテストに失敗します。
「何でやねん」と一瞬思ったりしますが、ModelNotFoundException
というのは、レポート対象になってないんですね。レポート対象とは、分かり易く言ってしまえば、ログの対象か否かですね。
例えば、findOrFail()
とか使って DB からモデルを取得しようとして見つからなくても、ログられない事からも ModelNotFoundException
はレポート対象外という事は分かりますね。
ソース的には、この辺で分かったりします。
という事で、新タイプの Exceptions facade は、従来からの expectException
と同じ目的で使えたりもしますが、ちょっと異なる所もあるぞ、という事が分かりました。
雑感
おかしな所等がありましたらコメント下さい。
Discussion