Ad

Laravel Phpunit Test Nested Eager Loading

- 1 answer

I have this nested relation im abit unsure how i assertJson the response within the phpunit test.

FilmController

public function show(string $id)
{
    $film = Film::with([
        'account.user:id,account_id,location_id,name',
        'account.user.location:id,city'
    ])->findOrFail($id);
}

FilmControllerTest

public function getFilmTest()
{
    $film = factory(Film::class)->create();

    $response = $this->json('GET', '/film/' . $film->id)
        ->assertStatus(200);

    $response
        ->assertExactJson([
            'id' => $film->id,
            'description' => $film->description,
            'account' => $film->account->toArray(),
            'account.user' => $film->account->user->toArray(),
            'account.user.location' => $film->account->user->location->toArray()
        ]);
}

Obviously this isnt working because its returning every column for the user im a little unfamiliar with how you test nested relations with the code you need so im unsure with a toArray can anyone help out?

Ad

Answer

Testing is a place where you throw DRY (don't repeat yourself) out and replace it with hard coded solutions. Why? simply, you want the test to always produce the same results and not be bound up on model logic, clever methods or similar. Read this amazing article.

Simply hard code the structure you expect to see. If you changed anything in your model to array approach, the test would still pass even thou your name was not in the response. Because you use the same approach for transformation as testing. I have tested a lot of Laravel apps by now and this is the approach i prefers.

$account = $film->account;
$user = $account->user;
$location = $user->location;

$response->assertExactJson([
    'description' => $film->description,
    'account' => [
        'name' => $account->name,
        'user' => [
          'name' => $user->name,
          'location' => [
            'city' => $location->city,
           ],
        ],
    ],
]);

Don't test id's the database will handle those and is kinda redundant to test. If you want to check these things i would rather go with assertJsonStructure(), which does not assert the data but checks the JSON keys are properly set. I think it is fair to include both, just always check the JSON structure first as it would likely be the easiest to pass.

$response->assertJsonStructure([
    'id',
    'description',
    'account' => [
        'id',
        'name',
        'user' => [
          'id',
          'name',
          'location' => [
            'id',
            'city',
           ],
        ],
    ],
]);
Ad
source: stackoverflow.com
Ad