LoginSignup
0
0

More than 3 years have passed since last update.

Laravel + PHPUnitでパスセグメント(パスパラメーター)を再現する

Posted at

ここのコードは実際には動作しないと思われます。
俺たちは雰囲気でコードを書いている。

例えば以下のように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

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