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?