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

bjones2015's avatar

Mocking A Form Request

I'm having trouble mocking out my form requests.

Can anyone see if I am doing something goofy?

$user = $this->setUpAdminAndAuthMock();
        $this->setPermission($user, 'create merchant');

        $request = Mockery::mock('App\Requests\CreateMerchant');
        $request->shouldReceive('passesAuthorization')
            ->once()
            ->andReturn(true);

        $request->shouldReceive('validate')
            ->once()
            ->andReturn(true);

        $this->app->instance('App\Requests\CreateMerchant', $request);

        $controller = Mockery::mock('App\Http\Controllers\Merchant\MerchantAdminController[store]');
        $controller->shouldReceive('store')
            ->once()
            ->andReturn();

        $this->app->instance('App\Http\Controllers\Merchant\MerchantAdminController', $controller);

        $this->post($this->getUrl());
0 likes
10 replies
bjones2015's avatar

Well the first mistake I made was in the path I passed to Mockery. I forgot the "Http" portion of the path.

The strange thing is though that if I tried to mock things like validate they were never hit, but just mocking the form request e.g.

$request = Mockery::mock('App\Http\Requests\UpdateMerchant');

$this->app->instance('App\Http\Requests\UpdateMerchant', $request);

was enough to pass through it. That doesn't seem right though ...

bobbybouwmann's avatar

Mocking facades is really hard. I would recommend, but that's just me, not the write the unit tests for controllers. Instead write integration or functional tests that test the complete controller function at once.

1 like
bjones2015's avatar

Yeah that's what I did originally, but since I was able to reuse the form requests in the admin route I was trying to avoid the redundancy of testing them twice.

1 like
usman's avatar

@bobbybouwmann

Mocking facades is really hard.

I don't see any facade involved here. I have not experienced any thing hard with mocking a facade in Laravel. Am I missing something here?

@bjones2015 why would you mock something that you are trying to test ( the controller )? By mocking the controller you are not testing anything here. Also since, you are already touching the functional boundary of the application there is no need to mock the request or validation. Just pass the valid input for the store method and make your assertion on the response and done :)

Usman.

bjones2015's avatar

@usman I just posted the relevant snippet so I could see where I might have caused confusion.

The thing is with this I'm not trying to test the controller, but rather the middleware. I have my controller tests in a different file in which I've turned off the middleware.

I mocked the controllers as I'm only testing if the middleware allows access or not so I'm not concerned about the controller response.

bobbybouwmann's avatar

@usman Since the OP didn't provided any code at the time I replied I assumed he was using the Request facade in his code!

1 like
bjones2015's avatar

Yeah sorry about that guys. I'll post the full code next time.

1 like
usman's avatar
usman
Best Answer
Level 27

@bobbybouwmann no worries :)

@bjones2015

The thing is with this I'm not trying to test the controller, but rather the middleware.

In this case, it is really simple to test, you don't need to mock any thing at all, since you are only interested in testing the functionality of the middleware.

I'm not concerned about the controller response.

IMHO, yes you do. Let me show you a simple example of testing the auth middleware that Laravel provides out of the box.

class ExampleTest extends TestCase
{

    public function test_admin_can_access()
    {
        $this->defineRoute();

        $user = User::first();
        $this->be($user);

        $this->get('admin-page');

        $this->assertResponseStatus(200);
    }

    public function test_guest_cannot_access()
    {
        $this->defineRoute();

        $this->get('admin-page');

        //expecting it to redirect us to login page.
        $this->assertResponseStatus(302);
    }

    protected function defineRoute()
    {
        $this->app['router']->get(
            'admin-page',
            [
                'middleware' => 'auth',
                function() {
                    return 'this is admin page';
                }
            ]
        );
    }
}

The idea here is to keep things simple. This is the freedom that functional tests give us so embrace it :).

Usman.

2 likes
bjones2015's avatar

Nice, I didn't realize you could override the routes like that! Much less clunky feeling that what I was doing.

1 like

Please or to participate in this conversation.