Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

auflyer2's avatar

Mocking Model Method

I have a test for the admin dashboard of the site. A user is required to complete their profile before continuing on the dashboard.

The User Model has a hasOne() relationship to Profile with the following method on User:

public function requiresProfile()
    {
        if(! $this->profile()->exists())
        {
            return true; //user needs to complete the profile
        }

        return false;
    }

Then in the controller:

class MembersController extends Controller
{
    public function index()
    {
        return auth()->user()->requiresProfile()
            ? redirect('/members/profile')
            : view('members.home');
    }
}

Finally the test:

/** @test */
    public function the_dashboard_page_redirects_to_the_profile_page_if_required() {

        $this->mock(User::class, function($mock){
            $mock->shouldReceive('requiresProfile')
                ->andReturn(true);
        });

        $response = $this->get('/members');

        $response->assertRedirect('/members/profile');

    }

The test was working when I type-hinted the Controller method like so:

public function index(User $user){
	return $user->requiresProfile()....etc
}

However that clearly won't work in production because $user needs to reference the Auth::user(), not a new instance.

I'm pretty new to testing, and can't seem to wrap my head around how to verify that this simple redirect works. Basically I just want to stub the requiresProfile() method to force it to return true or false, as necessary in the test, without modifying User or the Controller code.

I have found one workaround that involves creating a FakeUser::class and then swapping the instance for User in the container, hard-coding the method return as desired:

$this->swap(User::class, new FakeUser());

However this too breaks down, as it's brittle and hard to get an Auth'd user.

What is the best practice for testing a re-direct like this with the Model/Controller setup?

0 likes
2 replies
martinbean's avatar
Level 80

@auflyer2 The problem is, the user is not resolved from the container.

Instead, you could create a partial mock and use that user in your test, with an expectation:

$user = factory(User::class)->create();

$user = Mockery::mock($user)->makePartial();
$user->shouldReceive('requiresProfile')->andReturnTrue();

$this
    ->actingAs($user)
    ->get('/members')
    ->assertRedirect('/members/profile');
1 like
auflyer2's avatar

Very slick. I tried with mockPartial() per the Laravel docs, but was unable to set the return value to true. I just tried this out directly on Mockery and it works great.

Thanks!

1 like

Please or to participate in this conversation.