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

skeith22's avatar
Level 21

How to return a ValidationException from an Http::fake

Does anyone know how to return Illuminate\Validation\ValidationException from an Http::fake request?

For example you have this

$payload = [
    'first_name' => null,
    'last_name' => 'Doe'
];

Http::preventStrayRequests();

Http::fake([
    'api/v1/test-post' => Http::response([], 422)
    // return an Illuminate\Validation\ValidationException
]);

$respone = Http::post('api/v1/test-post', $payload);

// Check that validation failed here
// Like assertJsonValidationErrors(['first_name'])

I wanted to assert some validation errors for example, like first_name is required

I wanted to simulate how the API would respond without actually calling the API itself

or is there a different approach to assert some validation error using Http::fake?

0 likes
11 replies
LaryAI's avatar
Level 58

To simulate a ValidationException using Http::fake in your tests, you can return a response with a 422 status code and a JSON body that mimics the structure of a validation error response. Here's how you can do it:

  1. Define the fake response to include the validation error details.
  2. Use Http::fake to return this response when the specified endpoint is called.
  3. Assert that the response contains the expected validation errors.

Here's an example of how you can achieve this:

use Illuminate\Support\Facades\Http;
use Illuminate\Validation\ValidationException;

$payload = [
    'first_name' => null,
    'last_name' => 'Doe'
];

Http::preventStrayRequests();

Http::fake([
    'api/v1/test-post' => Http::response([
        'message' => 'The given data was invalid.',
        'errors' => [
            'first_name' => ['The first name field is required.']
        ]
    ], 422)
]);

$response = Http::post('api/v1/test-post', $payload);

// Check that validation failed here
$response->assertStatus(422);
$response->assertJsonValidationErrors(['first_name']);

In this example:

  • The Http::fake method is used to define a fake response for the api/v1/test-post endpoint.
  • The fake response includes a 422 status code and a JSON body that contains a message and errors array, mimicking the structure of a typical validation error response.
  • The assertJsonValidationErrors method is used to assert that the response contains validation errors for the first_name field.

This approach allows you to simulate a validation error response without actually calling the API, and you can assert that the validation errors are handled correctly in your application.

1 like
skeith22's avatar
Level 21

@laryai apparently Http::fake doesn't return an Illuminate\Test\TestResponse class, but a GuzzleHttp\Psr7\Response

Error: Call to undefined method GuzzleHttp\Psr7\Response::assertStatus()

and

Error: Call to undefined method GuzzleHttp\Psr7\Response::assertJsonValidationErrors()

any other way that Http::fake would return Illuminate\Test\TestResponse class?

Muhammad_Nawaz's avatar

How to Return a ValidationException from Http::fake() in Laravel When testing HTTP interactions in Laravel, you might want to simulate a ValidationException that would typically be triggered by a validation error response from an external API. You can easily achieve this using Http::fake() to return a 422 response with a structure that Laravel recognizes as a validation error.

Here’s how you can do it:

use Illuminate\Http\Client\Request; use Illuminate\Http\Client\RequestException; use Illuminate\Support\Facades\Http; use Illuminate\Validation\ValidationException;

// Fake an HTTP request for testing Http::fake([ 'example.com/*' => function (Request $request) { // Simulate a validation error response with a 422 status code. return Http::response([ 'message' => 'The given data was invalid.', 'errors' => [ 'field_name' => ['The field_name field is required.'], ], ], 422); }, ]);

// Example usage try { Http::post('example.com/api/endpoint', [ 'field_name' => '', // Invalid data to trigger validation error ]); } catch (RequestException $e) { $response = $e->response;

if ($response->status() === 422) {
    // Throw a ValidationException with the error messages
    throw ValidationException::withMessages($response->json('errors'));
}

throw $e;

} Explanation: Http::fake: Allows you to fake HTTP requests for testing purposes. The closure here simulates a fake response for any request to example.com/*.

Http::response: Returns a fake HTTP response with a 422 status code, along with a validation error structure that Laravel expects.

RequestException Handling: If a RequestException is caught, we check if the status is 422. If so, we manually throw a ValidationException using ValidationException::withMessages().

Writing a Test If you're testing this behavior, you can directly assert the ValidationException as follows: public function test_example_endpoint_validation_error() { Http::fake([ 'example.com/*' => function (Request $request) { return Http::response([ 'message' => 'The given data was invalid.', 'errors' => [ 'field_name' => ['The field_name field is required.'], ], ], 422); }, ]);

$this->expectException(ValidationException::class);

Http::post('example.com/api/endpoint', [
    'field_name' => '', // Invalid data
]);

} In this test, a ValidationException is expected to be thrown, ensuring your fake response accurately simulates a validation error scenario.

2 likes
skeith22's avatar
Level 21

@muhammad_nawaz how about returning a different exception? like for example CustomException when some went wrong in the the MyController@customMethod

Http::fake([
    'api/v1/test-post' => Http::response([
        // return CustomException::class here
    ], 403)
]);

how would you do that?

Tray2's avatar

@skeith22 Are you using form request to validate the input, in that case you can test them like this.

it('fails if the title is missing', function () {
    $this->formRequest(RecordFormRequest::class)
        ->post(['title' => ''])
        ->assertValidationFailed()
        ->assertValidationMessages(['The title field is required.']);
});
1 like
skeith22's avatar
Level 21

@Tray2 can you convert this to a PHPUnit test?

why does it feels like Pest Testing is much easier? I don't see these kinds of sample tests on the Testing page of Laravel. they need to somehow deepen the explanation in the Testing page

skeith22's avatar
Level 21

@Tray2 I see, it's not built-in in Laravel, apparently I can't freely install packages on the current project.

but do you happen to know how to test private methods in a partialMock?

Snapey's avatar

You are mocking the Http call so no call to the api endpoint will be made. You could throw an exception in the mock, but then, Im not sure what you are testing exactly?

1 like
martinbean's avatar

@skeith22 The Http facade is used to make HTTP requests. HTTP requests return HTTP response statuses and bodies, not PHP exceptions. A Laravel Illuminate\Validation\ValidationException exception is converted to either a redirect or JSON response; the exception isn’t “returned” from the HTTP request itself.

1 like

Please or to participate in this conversation.