0

I am testing my Laravel application with the integrated PHPUnit configuration and I have problems with the authentication of a user inside a test.

I have this test (shortened)

public function testShowEditForm($user, $expectedStatus, $expectedLocation, $expectedSee, $expectedDontSee) {
    if ($user !== null)
        $this->actingAs($user);

    // $this->assertAuthenticatedAs($user); -> This is true!

    $response = $this->get("/objects/edit/");

    $response->assertStatus($expectedStatus);

    // [...]
}

with this data provider:

public function showEditFormProvider() {
    return [
        'allowedUser' => [
            UserGenerator::getControllingUser(),
            200,
            null,
            ["something"],
            []
        ]
    ];
}

The UserGenerator::getControllingUser() just triggers the User Factory, adds some rights and returns the user object.

The tested method (also shortened):

public function edit($object_id = null) {
    $user = User::find(Auth::user()->id); // Auth::user() returns null
    // [...]
}

The route for this method is encapsuled inside the "middleware" => "auth" part in the routes/web.php

Problem: The data provider is correctly called, it passes the middleware but the Auth::user() call in the edit() method returns null - so the authentication seems to have failed anyway regardless the passing through the middleware?

  • If I replace the parameter $user in the testShowEditForm directly with UserGenerator::getControllingUser(), it works (but this isn't a good workaround because I have a lot of test cases and so I need the data providers).
  • So I worked around by calling the data provider by $this->showEditFormProvider() in the first line of the test method testShowEditForm() - but it gets called twice (what is the correct behaviour according to this 1). But this is also not the ideal workaround, because if I create an object in the provider to test, it gets created also twice and so the assertions fail.

Is there anything I'm doing wrong? I already searched a lot for this topic and the actingAs()/be() methods in the testing method seem to be the best practice for mocking a logged in user.

1 "All data providers are executed before both the call to the setUpBeforeClass static method and the first call to the setUp method." https://phpunit.de/manual/3.7/en/writing-tests-for-phpunit.html

DSharp
  • 58
  • 1
  • 5
  • Auth::shouldReceive('user')->andReturn($user); it's type of mocking but I'm using it usually in unit testing not functional testing. You can also give it a try. – Mohammad.Kaab Dec 28 '19 at 09:58

1 Answers1

0

In Laravel 5.8 it worked using

$user = User::find(Auth::id());

instead of

$user = User::find(Auth::user()->id); // Auth::user() returns null

inside the Controller. I have no idea why, but maybe it will help some searching dev in the future. Funnily enough, since Laravel 6 (currently my app is on 6.10.0), no more problems, even with the "old" implementation.

DSharp
  • 58
  • 1
  • 5