Mastering Guzzle MockHandler: 5 Practical Techniques for Effective HTTP Testing in PHP

  1. Simulating Sequential Responses with Response Queues

The MockHandler in Guzzle allows developers to simulate a series of HTTP responses by defining a response queue. This is particularly useful when testing code that makes multiple sequential API calls. By passing an array of Response instances to the MockHandler, each request made through the client will return the next response in the list.

use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\Psr7\Response;

$mock = new MockHandler([
    new Response(200, [], 'First response'),
    new Response(500, [], 'Server error'),
    new Response(204)
]);

This approach ensures your application logic correctly handles varying responses across consecutive requesst, such as retry mechanisms or fallback behaviors.

  1. Testing Error Scenarios Using Exceptions

To verify that your application gracefully handles network issues or server failures, you can inject exceptions directly into the mock queue. This enables comprehensive testing of error-handling paths without relying on real network conditions.

use GuzzleHttp\Exception\RequestException;
use Psr\Http\Message\RequestInterface;

$mock = new MockHandler([
    new RequestException('cURL error', $request),
    new RequestException('Timeout exceeded', $request)
]);

By simulating exceptions like RequestException or ConnectException, you can assert that your service layer responds appropriately—logging errors, triggering retries, or returning user-friendly messages.

  1. Dynamic Response Generation via Callable Handlers

For advanced use cases where responses depend on request parameters, headers, or body content, MockHandler supports callable functions within the queue. These callables receive the current RequestInterface and options array, enabling conditional logic to generate context-aware responses.

$mock = new MockHandler([
    function (RequestInterface $request, array $options) {
        $path = $request->getUri()->getPath();

        if ($path === '/api/users') {
            return new Response(200, ['Content-Type' => 'application/json'], 
                json_encode(['users' => [['id' => 1, 'name' => 'John']]]));
        }

        if ($path === '/api/users/1') {
            return new Response(200, [], '{"id":1,"name":"John"}');
        }

        return new Response(404);
    }
]);

This technique is ideal for testing route-specific behavior, authentication checks, or payload validation logic based on incoming requests.

  1. Monitoring Test Execution with Lifecycle Callbacks

MockHandler provides optional callbacks for observing the outcome of each handled request. The $onFulfilled and $onRejected hooks are triggered upon successful or failed requests respectively, allowing you to capture execution details for assertions or debugging.

$collectedStatuses = [];
$collectedErrors = [];

$mock = new MockHandler(
    [new Response(201), new RequestException('Failed', $request)],
    function ($response) use (&$collectedStatuses) {
        $collectedStatuses[] = $response->getStatusCode();
    },
    function ($exception) use (&$collectedErrors) {
        $collectedErrors[] = $exception->getMessage();
    }
);

These callabcks are valuable for validating side effects, measuring performance characteristics during test runs, or asserting how often certain endpoints are accessed.

  1. Streamlining Integration Tests with Prebuilt Middleware Stacks

When testing services that rely on Guzzle's middleware stack (e.g., redirect handling, cookies, or logging), manually constructing the handler chain can be cumbersome. The static method createWithMiddleware() simplifies this by automatically wrapping the MockHandler inside a fully configured HandlerStack.

use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;

$handlerStack = MockHandler::createWithMiddleware([
    new Response(200, [], '{"status":"ok"}')
]);

$client = new Client(['handler' => $handlerStack]);
$response = $client->get('/test-endpoint');

echo $response->getBody(); // Outputs: {"status":"ok"}

This setup mimics production-like environments while retaining full control over HTTP interactions, making it perfect for integration-level unit tests.

Tags: Guzzle PHP HTTP Client MockHandler Unit Testing HTTP Simulation

Posted on Sat, 16 May 2026 06:33:10 +0000 by DotSPF