Laravel PHPUnit mock Request

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company
Title: Laravel PHPUnit Mock Request for Controllers: A Comprehensive Guide Body:

As a senior developer working on a Laravel application, you may encounter situations where you need to test your controller logic using PHPUnit tests. Among the various aspects to consider is correctly mocking and controlling the Request object in your PHPUnit tests. In this blog post, we'll explore how to achieve this effectively while ensuring accurate results.

Testing Controller Logic with Mock Requests

To begin, let's first review a basic Laravel controller and an associated test case involving the Request object:
use Illuminate\Http\Request;

public function insert(Request $request)
{
    // ... some codes here
    if ($request->has('username')) {
        $userEmail = $request->get('username');
    } else if ($request->has('email')) {
        $userEmail = $request->get('email');
    }
    // ... some codes here
}
public function testIndex()
{
    // ... some codes here
    $requestParams = [
        'username' => 'test',
        'email'    => 'test@test.com'
    ];

    $request = $this->getMockBuilder('Illuminate\Http\Request')
        ->disableOriginalConstructor()
        ->setMethods(['getMethod', 'retrieveItem', 'getRealMethod', 'all', 'getInputSource', 'get', 'has'])
        ->getMock();

    $request->expects($this->any())
        ->method('get')
        ->willReturn($requestParams);

    $request->expects($this->any())
        ->method('has')
        ->willReturn($requestParams);

    $request->expects($this->any())
        ->method('all')
        ->willReturn($requestParams);

    // ... some codes here
}

Understanding the Issue with Mock Requests and the Expected Outcome

The problem lies in how PHPUnit handles Request objects within controller tests. The code shown earlier correctly mocks a Request object, but it doesn't work as intended. When executing this test case, the has('username') method call always returns true because the provided mock request has the username key present in its array. Similarly, if we remove the 'username' key from $requestParams and re-run the test, the request will still be considered valid for having a 'username', as it contains an empty array with that key. This isn't ideal because we want to verify that the Request object has a specific value or key under certain conditions in our tests.

Implementing Correct Mock Requests

To achieve the intended behavior, we need to update the PHPUnit test code for `insert()` as follows:
public function testIndex()
{
    // ... some codes here
    $requestParams = [
        'username' => 'test',
        'email'    => 'test@test.com'
    ];

    $requestParamsWithoutUsername = array_diff($requestParams, ['username']);

    $request = $this->getMockBuilder('Illuminate\Http\Request')
        ->disableOriginalConstructor()
        ->setMethods(['getMethod', 'retrieveItem', 'getRealMethod', 'all', 'getInputSource', 'get', 'has'])
        ->getMock();

    $request->expects($this->any())
        ->method('get')
        ->willReturn(isset($requestParamsWithoutUsername['username']) ? $requestParamsWithoutUsername['username'] : null);

    $request->expects($this->any())
        ->method('has')
        ->willReturn(function ($key) use ($requestParams, $requestParamsWithoutUsername) {
            return isset($requestParams[$key]) || (isset($requestParamsWithoutUsername[$key]) && !isset($requestParams[$key]));
        });

    // ... some codes here
}
This test case now accurately handles the Request object in our controller logic. When calling `has('username')`, it will return true if the username key is present in $requestParams, and false if it's in $requestParamsWithoutUsername (without having a 'username' key explicitly). This ensures that we are testing the correct behavior for various scenarios and can make assertions based on the presence of specific keys or values within our Request object.

Conclusion

In this blog post, we have explored the issue with mocking requests in Laravel PHPUnit tests, detailed a potential solution, and emphasized the importance of accurately modeling the Request object for effective testing. By following these guidelines, you can enhance your unit test coverage and maintain reliable code quality throughout your Laravel application.