Search code examples
phplaravelunit-testingcontrollerphpunit

Wrong request parameters when testing an api route


I have a test that calls a function in a controller:

public function testAuthentication()
{
    $user = $this->createUser();
    $this->actingAs($user)->withoutMiddleware();
    $project = $user->project();
    ...
    $response = $this->post("/api/projects/$project->id/store", [
        'param' => 'testparam'
    ]);
    ...
}

The route looks like this:

Route::group(['prefix' => 'projects'], function () {
    Route::group(['prefix' => '{project}'], function () {
        Route::post('store', [MyController::class, 'store']);
    });
});

And the function store looks like this:

public function store(Request $request, Project $project): void
{
    dd($project);
    ...
}

When i start the test and i debug the controller function, i can see that $project is empty, meaning it doesnt have any attribute. However when i change the function header to:

public function store(Request $request, string $project): void
{
    ...
    MyModel::create([
        ...
        'project_id' => $project->id
    ]);
])

and i debug, i get the right id.

When i call this function normally from the browser request it works, but when i call it from the test file it only works with string

Any ideas? Thanks in advance.


Solution

  • Wait, what are you getting when you have Project instead of string, because "is empty" could mean that it is a Project with no data (no attributes, just the object) or it is null, and the later would make no sense... What database connection are you using?

    If I am not confused, you are using withoutMiddleware and that is removing the Middleware that is doing the implicit binding, so you will always get an empty Project object, so remove withoutMiddleware and try it again...

    You can see you have a middleware doing the binding replacement, and that middleware's code is explicit about doing so. Well, withoutMiddleware is removing it, so you will just have the normal Dependency Injection behavior.

    Personally, if you have to use withouthMiddleware, it should either be a Unit test (instead of a feature) or define everything you are expecting to have on that route you are asserting, else you are defining half the data your case needs, and that is not good (for a Feature test).