ここのコードは実際には動作しないと思われます。
俺たちは雰囲気でコードを書いている。
例えば以下のようにURLを設定します。
routes.php
Route::get('/{user_id}', 'UserController@show');
Route::get('/{user_id}/edit', 'UserController@edit');
Route::get('/{user_id}/hoge', 'UserController@hoge');
Route::get('/{user_id}/fuga', 'UserController@fuga');
ユーザーが存在しなければ例外とします。
必然的にUserクラスは1つしか存在してはいけないので、ServiceProviderでsingletonにします。
AppServiceProvider.php
public function boot() {
$this->app->singleton(User::class, function() {
return (app()->make(UserService::class))
->findUser();
});
}
UserService.php
public function findUser()
{
$user = User::find(request()->route()->parameter('user_id'));
if (is_null($user)) {
throw new NotFoundException('ユーザーが見つかりません');
}
return $user;
}
これでどのクラスからでもapp()->make(User::class)
でユーザー情報が取得できるようになりました。
なお、あくまで例としてUserクラスを挙げていますが、Laravelでは認証済みユーザーはAuth::user()
で取ってこれます。
以下、本題のテストのお話です。
単にリクエストをテストするだけなら簡単です。
Feature/UserTest.php
/**
* @test
*/
public function ユーザーがいなければ404になること()
{
$response = $this->get('/should_404');
$response->assertStatus(404);
}
ではfindUser
を単体テストするにはどうすれば良いでしょうか。
単純にfindUserメソッドを呼ぶと、request()->route()
の時点でnullが返ってくるため->parameter('user_id')
で例外になります。
結論として、事前にRequestを疑似的に再現して対処します。
Unit/UserTest.php
/**
* @test
*/
public function 指定されたユーザーがいなければNotFoundExceptionになること()
{
$this->expectException(NotFoundException::class);
request()->setRouteResolver(function () {
return (new Route('POST', '/{user_id}', []))->bind(
new Request([], [], [], [], [], ['REQUEST_URI' => '/should_not_found'])
);
});
(app()->make(UserService::class))->findUser();
}
参考:
Simulate a http request and parse route parameters in Laravel testcase