6

I'm trying to test a function that depends on

$request->all();

in a method. How do I mock the Request class so $request->all(); returns

['includes' => ['some_val','another_val'] 

in tests?

Jenski
  • 1,458
  • 1
  • 18
  • 29

4 Answers4

5

I recommend you to use mockery/mockery. You will have to do this:

In your test method do:

app()->bind(
    \Illuminate\Http\Request::class,
    function () {
        $mock = \Mockery::mock(\Illuminate\Http\Request::class)->makePartial();
        $mock->shouldReceive('all')
            ->andReturn(['includes' => ['some_val', 'another_val']]);

        return $mock;
    }
);

What you are doing there is:

  • Binding the mock to the Request, so when you do yourMethod(Request $request) it will instantiate your mock instead of the real class
  • Doing \Mockery::mock(CLASS)->makePartial(); will first create a mock of that class, and then (makePartial()) will allow you to use other non-mocked methods (use real methods) so any method you didn't mock will run real code
  • shouldReceive will allow the mocked class to mock that method (argument of shouldReceive), so we are mocking all method and returning your desired value, in this case, the array you posted
  • And finally we must return the mock as the instance

As @devk stated, Laravel does not recommend mocking Request class, so don't do it, but if you need to mock any other object, you can use the code above and it will perfectly work.

matiaslauriti
  • 7,065
  • 4
  • 31
  • 43
2

Per https://stackoverflow.com/a/61903688/135114, if

  1. your function under test takes a $request argument,
  2. you don't need to do funky stuff to the Request—real paths are good enough for you

... then you don't need to "mock" a Request (as in, mockery),
you can just create a Request and pass it, e.g.

public function test_myFunc_condition_expectedResult() {
    ...
    $mockRequest = Request::create('/path/that/I_want', 'GET'); 
    $this->assertTrue($myClass->myFuncThat($mockRequest));
}
Daryn
  • 4,791
  • 4
  • 39
  • 52
0

As stated by devk, don't mock the request. But Laravel allows you to build an actual request and then call your controller in your test like this:

public function testPostRequest() {
    $response = $this->post(
        '/my-custom-route',
        ['includes' => ['some_val','another_val']]
    );
}
Christopher Thomas
  • 4,424
  • 4
  • 34
  • 49
Michiel
  • 2,143
  • 1
  • 21
  • 21
0

This works well, for a mock or you can do as above with the partial depending on if you want the request object to pass around or inspect

/** @var \Illuminate\Http\Request|\Mockery\MockInterface */
        $request = $this->mock(Request::class, function (MockInterface $mock) {
            $mock->shouldReceive('all')
                ->once()
                ->andReturn([
                    'includes' => [
                        'some_val', 'another_val',
                    ],
                ]);
        });
Garrick Crouch
  • 309
  • 4
  • 11