VOOZH about

URL: https://deepwiki.com/friendsofhyperf/components/4.2-testing-with-fakes-and-assertions

⇱ Testing with Fakes and Assertions | friendsofhyperf/components | DeepWiki


Loading...
Last indexed: 14 February 2026 (15d5ca)
Menu

Testing with Fakes and Assertions

This document explains the HTTP Client component's testing infrastructure, which enables complete request stubbing and assertion capabilities for test environments. The faking system intercepts outgoing HTTP requests and returns predefined responses without making actual network calls, while the assertion API validates that requests were sent with expected parameters.

For information about building and executing actual HTTP requests, see Request Building and Execution. For retry logic and error handling in production scenarios, see Retry Logic and Error Handling.


Overview of the Testing Infrastructure

The HTTP Client provides a comprehensive fake-and-assert pattern modeled after Laravel's HTTP testing utilities. The system operates through three main components: the Factory class that manages stub callbacks, the PendingRequest class that intercepts requests via handler middleware, and assertion methods that validate request/response pairs recorded during test execution.


Sources: src/http-client/src/Factory.php74-488 src/http-client/src/PendingRequest.php1030-1064 src/http-client/src/Http.php106-217


Fake Registration Methods

Basic Fake Registration

The Http::fake() method initializes the testing infrastructure and registers stub callbacks. When called without arguments, it returns a 200 OK response for all requests. The method accepts a callback function, a URL pattern map, or null.


Sources: src/http-client/src/Factory.php236-274 src/http-client/src/Http.php136-141

The Factory::fake() method implementation shows three paths:

  1. Null argument (lines 242-246): Creates a default callback returning Factory::response()
  2. Array argument (lines 248-253): Iterates through URL patterns calling stubUrl() for each
  3. Closure argument (lines 256-271): Wraps the closure to handle promise resolution and transfer stats

All paths merge stub callbacks into stubCallbacks collection and enable recording mode by calling record() which sets recording = true src/http-client/src/Factory.php472-477

Sources: src/http-client/src/Factory.php236-274 tests/HttpClient/HttpClientTest.php79-86

URL Pattern Stubbing

The Http::stubUrl() method registers a stub for a specific URL pattern using wildcard matching. The pattern uses Str::is() for matching, supporting * as a wildcard character.


Sources: src/http-client/src/Factory.php296-307

The implementation at src/http-client/src/Factory.php298-306 shows that when the URL doesn't match, the callback returns null (implicit), allowing the stub handler to continue checking subsequent patterns. The pattern is prefixed with * via Str::start() to ensure flexible matching.

Test examples:

  • 'foo.com/*' matches 'http://foo.com/test'
  • 'bar.com/*' matches 'http://bar.com/test'
  • '*' matches any URL (fallback pattern)

Sources: tests/HttpClient/HttpClientTest.php395-415

Preventing Stray Requests

The Http::preventStrayRequests() method enforces strict request faking by throwing a RuntimeException if any request is attempted without a matching stub. This is essential for ensuring comprehensive test isolation.


Sources: src/http-client/src/Http.php162-167 src/http-client/src/PendingRequest.php1046-1048 src/http-client/src/Factory.php315-320

The enforcement happens in PendingRequest::buildStubHandler() at lines 1046-1048. When no stub callback returns a response and preventStrayRequests is true, the exception is thrown with the attempted URL. The flag is passed from Factory to PendingRequest via the stub() and preventStrayRequests() methods at construction time.

Sources: src/http-client/src/PendingRequest.php1112-1130 src/http-client/src/Factory.php148-150


Response Sequences

The ResponseSequence class enables testing scenarios where multiple requests to the same endpoint should return different responses in a specific order. Each invocation shifts a response off the internal array.

ResponseSequence Architecture


Sources: src/http-client/src/ResponseSequence.php1-157 src/http-client/src/Factory.php225-228

Sequence Methods

The ResponseSequence provides fluent builder methods for constructing response sequences:

MethodParametersDescription
push()$body, $status, $headersPush response with body (array or string)
pushStatus()$status, $headersPush response with only status code
pushFile()$filePath, $status, $headersPush response with file contents as body
pushResponse()$responsePush raw promise/response object
whenEmpty()$responseSet fallback response when sequence exhausted
dontFailWhenEmpty()-Allow empty sequence (returns default 200 OK)
isEmpty()-Check if sequence is exhausted

Sources: src/http-client/src/ResponseSequence.php78-156

Sequence Invocation Behavior

When used as a stub callback, the ResponseSequence is invoked via its __invoke() method src/http-client/src/ResponseSequence.php59-70 The behavior depends on the sequence state:

  1. Has responses: array_shift() removes and returns first response
  2. Empty + failWhenEmpty=true: Throws OutOfBoundsException
  3. Empty + failWhenEmpty=false: Returns emptyResponse or Factory::response()

Test example from tests/HttpClient/HttpClientTest.php739-770 demonstrates all three states:

  • First call returns 'Ok' with status 201
  • Second call returns JSON ['fact' => 'Cats are great!']
  • Third call returns file contents
  • Fourth call returns status 403
  • Fifth call throws OutOfBoundsException

Sources: src/http-client/src/ResponseSequence.php59-70 tests/HttpClient/HttpClientTest.php739-770


Stub Handler Implementation

The stub handler is injected into the Guzzle handler stack via PendingRequest::buildStubHandler() and pushHandlers(). It intercepts requests before they reach the actual HTTP transport layer.

Handler Stack Architecture


Sources: src/http-client/src/PendingRequest.php956-991 src/http-client/src/PendingRequest.php1030-1064

Stub Callback Invocation Chain

The stub handler at src/http-client/src/PendingRequest.php1037-1063 performs these operations:

  1. Map over stubCallbacks: Each stub is invoked with (Request, options)
  2. Filter nulls: Remove stubs that didn't match (returned null)
  3. Take first: Use first non-null response
  4. Null handling: If all stubs returned null, check preventStrayRequests
  5. Array conversion: Convert array responses to JSON promises via Factory::response()
  6. Sink support: If response should be saved to file, attach sink handler

The recorder handler at src/http-client/src/PendingRequest.php1012-1027 wraps the response in a promise that calls factory->recordRequestResponsePair(), storing the interaction in Factory::$recorded for later assertions.

Sources: src/http-client/src/PendingRequest.php1030-1064 src/http-client/src/PendingRequest.php1012-1027


Assertion Methods

The Factory class provides PHPUnit-style assertion methods that inspect the recorded array to verify request behavior. All assertions use PHPUnit::assertTrue(), PHPUnit::assertFalse(), or PHPUnit::assertCount() internally.

Core Assertion Methods


Sources: src/http-client/src/Factory.php356-455

Assertion Method Details

MethodBehaviorImplementation
assertSent(callback)Passes if callback returns true for any recorded pairPHPUnit::assertTrue(recorded(callback)->count() > 0) Factory.php360-365
assertNotSent(callback)Passes if callback returns false for all recorded pairsPHPUnit::assertFalse(recorded(callback)->count() > 0) Factory.php394-399
assertNothingSent()Passes if no requests were recordedPHPUnit::assertEmpty(recorded) Factory.php405-410
assertSentCount(count)Passes if exact number of requests recordedPHPUnit::assertCount(count, recorded) Factory.php418-421
assertSentInOrder(callbacks)Passes if callbacks match recorded orderIterates and asserts each callback against recorded[index] Factory.php373-387
assertSequencesAreEmpty()Passes if all ResponseSequences exhaustedChecks isEmpty() on all sequences in responseSequences Factory.php426-434

Sources: src/http-client/src/Factory.php356-434

Request Callback Inspection

Assertion callbacks receive (Request $request, Response $response) parameters. The Request wrapper provides inspection methods:


Sources: src/http-client/src/Request.php1-311

Test examples showing typical assertion patterns:


Sources: tests/HttpClient/HttpClientTest.php411-415 tests/HttpClient/HttpClientTest.php428-434 tests/HttpClient/HttpClientTest.php650-655


Complete Testing Workflow

The following diagram illustrates a complete test workflow from fake registration through assertion validation:


Sources: tests/HttpClient/HttpClientTest.php395-415 src/http-client/src/Factory.php236-274 src/http-client/src/PendingRequest.php860-925

Test Isolation Pattern

Each call to Http::fake() resets the recorded state by setting recorded = [] at src/http-client/src/Factory.php240 This ensures test isolation:


Sources: tests/HttpClient/HttpClientTest.php568-583


Advanced Faking Patterns

Conditional Response Logic

Stub callbacks can implement complex conditional logic by inspecting the Request object and options array:


Sources: src/http-client/src/Factory.php257-270

Wildcard Pattern Precedence

When multiple URL patterns are registered, they are checked in registration order. The first matching pattern's callback is used:


This works because stubUrl() calls are processed in array iteration order, and stubs are checked via stubCallbacks->map() which maintains insertion order.

Sources: src/http-client/src/Factory.php248-253 tests/HttpClient/HttpClientTest.php395-415

Response Data Transformation

The stub handler automatically converts array responses to JSON promises at src/http-client/src/PendingRequest.php1053:


The conversion happens via Factory::response($array) which:

  1. JSON-encodes the array
  2. Sets Content-Type: application/json header
  3. Wraps in a Psr7Response with status 200

Sources: src/http-client/src/Factory.php207-218 src/http-client/src/PendingRequest.php1053

TransferStats Population for Fakes

When a fake response is a PromiseInterface, the stub callback in Factory::fake() populates transfer statistics via the on_stats callback at lines 263-266:


This ensures that code checking transfer stats (e.g., $response->effectiveUri()) works correctly even with faked responses.

Sources: src/http-client/src/Factory.php262-267 src/http-client/src/Response.php198-201


Response Method Reference

The Response class provides methods for inspecting response state in assertion callbacks:

CategoryMethodsDescription
Status Checksstatus(), successful(), ok(), redirect(), failed(), clientError(), serverError()HTTP status inspection
Status Assertionscreated(), accepted(), noContent(), movedPermanently(), found(), notModified(), badRequest(), unauthorized(), forbidden(), paymentRequired(), notFound(), requestTimeout(), conflict(), unprocessableEntity(), tooManyRequests()Specific status code checks via DeterminesStatusCode trait
Body Accessbody(), json(), object(), collect(), fluent()Response body parsing
Headersheader(), headers()Header access
Metadatacookies(), effectiveUri(), handlerStats()Request metadata

Sources: src/http-client/src/Response.php1-458 src/http-client/src/Concerns/DeterminesStatusCode.php

Test assertions commonly check these response methods:


Sources: tests/HttpClient/HttpClientTest.php79-100