michiruf / laravel-http-automock
Automatically mock http requests when testing
Fund package maintenance!
Requires
- php: ^8.2
- illuminate/contracts: ^11.0||^12.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^3.2
- laravel/pint: ^1.14
- laravel/sail: ^1.31
- nunomaduro/collision: ^8.1.1||^7.10.0
- orchestra/testbench: ^10.4.0
- pestphp/pest: ^3.0
- pestphp/pest-plugin-laravel: ^3.0
- slim/slim: ^4.14
- spatie/laravel-ray: ^1.35
- dev-main
- 0.2
- 0.2-rc7
- 0.2-rc6
- 0.2-rc5
- 0.2-rc4
- 0.2-rc3
- 0.2-rc2
- 0.2-rc1
- 0.1
- dev-doc
- dev-dependabot/github_actions/dependencies-5ace8927c2
- dev-refactor-options
- dev-indipendent-dispatcher
- dev-ci
- dev-scopes
- dev-separate-options-magic2
- dev-operational-flags
- dev-separate-options-trait
- dev-separate-options-magic
- dev-xdebug-compat
This package is auto-updated.
Last update: 2026-03-07 12:09:07 UTC
README
Automatically record and replay HTTP responses in your Laravel tests. On the first test run, real HTTP requests are
made and the responses are saved to disk. On subsequent runs, the saved responses are used instead, no real requests
are made. This makes your tests faster, deterministic, and independent of external services. Automock is fully
compatible with Http::fake().
Requires PHP 8.2+, Laravel 11+, and Pest. Works only with Laravel's HTTP client.
Quick Start
Installation
composer require michiruf/laravel-http-automock --dev
Optionally publish the config:
php artisan vendor:publish --tag="http-automock-config"
Usage
Call Http::automock() inside your test before executing HTTP requests. Responses will be automatically saved on
the first run and replayed on subsequent runs.
it('can do stuff with the api', function () { Http::automock(); $response = Http::get('https://api.sampleapis.com/coffee/hot')->json(); expect($response)->toHaveCount(20, 'There are not 20 hot coffees in the api service'); });
For more test examples, see the example test.
How It Works
- You call
Http::automock()in a test, which registers the recording/replaying handlers - When an HTTP request is made:
- If a mock file exists for that request, the saved response is returned (no real request)
- If no mock file exists, the real request is made and the response is saved to disk
- Mock files are stored per-test in a directory structure like:
tests/.pest/automock/TestScope/ExampleTest/it_can_do_stuff_with_the_api/1_GET_4c147242.mock
Motivation
When testing applications that depend on external APIs, you often end up manually capturing response data to feed
into Http::fake(). This is tedious, especially when services return large or complex payloads. Running real
requests in tests ensures your application actually works against live data, but the execution time is high, and
maintaining both faked and real test setups creates significant overhead.
Laravel Http Automock removes that burden. On the first run, your tests hit the real APIs and responses are saved automatically. Every subsequent run replays those responses instantly. You get the confidence of real data without the cost of real requests. The concept is similar to snapshot testing, except that instead of persisting the test output, Automock persists the input.
Since mock files live in your repository, Git naturally picks up changes in external API responses which makes it easy to notice when a service changed its behavior while keeping a safe copy of the data.
Configuration
Each feature can be configured via three methods (in order of precedence):
- Fluent API:
Http::automock()->someFeature()orHttp::configureAutomock()->someFeature() - CLI:
./vendor/bin/pest --automock-option - Config:
config/http-automock.php(if published)
Note
Http::automock() both enables Automock and returns the instance for fluent configuration.
Http::configureAutomock() returns the instance without enabling Automock, useful for setting options separately.
Reference
In addition to the publishable config http-automock.php, you can use these methods to configure Automock:
| Feature | Fluent API | CLI Flag | Default |
|---|---|---|---|
| Enable | Http::automock() |
--automock-enabled |
off |
| Disable | ...->disable() / Http::noAutomock() |
— | — |
| Directory | — | --automock-directory=... |
'.pest/automock' |
| Extension | — | --automock-extension=... |
'.mock' |
| Shared | ...->shared() |
--automock-shared |
false |
| Shared directory | — | --automock-shared-directory=... |
'.pest/automock/Shared' |
| Prettify dir naming | ...->prettifyDirectoryNaming() |
--automock-prettify-directory-naming |
false |
| File name resolver | ...->resolveFileNameUsing(...) |
--automock-file-name-resolver=... |
'stack' |
| Headers | ...->withHeaders(...) |
--automock-headers=... |
off / [] |
| Renew | ...->renew() |
--automock-renew |
false |
| Prevent auto renew | ...->preventAutoRenew() |
--automock-prevent-auto-renew |
false |
| Prune | ...->prune() |
--automock-prune |
false |
| Prevent real requests | ...->preventRealRequests() |
--automock-prevent-real-requests |
false |
| Prevent unknown requests | ...->preventUnknownRealRequests() |
--automock-prevent-unknown-real-requests |
false |
| Skip (URL pattern) | ...->skip('pattern', 'alias') |
--automock-url-filters=... |
[] |
| Skip GET/POST/... | ...->skipGet(), ...->skipPost(), etc. |
— | — |
| Validate mocks | ...->validateMocks() |
--automock-validate-mocks |
false |
| Mock HTTP fakes | ...->mockHttpFakes() |
--automock-mock-http-fakes |
false |
| JSON pretty print | ...->jsonPrettyPrint() |
--automock-json-pretty-print |
true |
Enable / Disable
Automock is not active by default. It must be explicitly enabled per-test by calling Http::automock(). To disable
Automock afterward, use disable() or Http::noAutomock().
File Name Resolvers
Each mock file needs a unique filename so that requests can be matched to their saved responses. File name resolvers
control how these filenames are generated from the request properties (URL, method, body, etc.). The default stack
resolver produces filenames like 1_GET_4c147242.mock by combining a request counter, HTTP method, and URL hash.
You can switch to a different resolver, combine multiple resolvers, or provide your own logic entirely - either via a named resolver from the config, a closure, or a resolver class instance.
Available resolvers: stack, count, http_method, url_hash, url_subdirectory, data_hash
Using a named resolver:
Http::automock()->resolveFileNameUsing('url_subdirectory'); // Creates: .../api.example.com/coffee/hot.mock
Using a closure:
Http::automock()->resolveFileNameUsing(fn (Request $request, bool $forWriting) => "TEST-{$request->method()}"); // Creates: .../TEST-GET.mock
Using a resolver class:
Http::automock()->resolveFileNameUsing(new RequestUrlResolver(port: false, removeSlashes: false)); // Creates: .../localhost/coffee/hot.mock
Using resolver with custom arguments:
Http::automock()->resolveFileNameUsingResolverAndArgs( RequestUrlResolver::class, ['port' => false, 'removeSlashes' => false] );
Configuring the stack resolver:
The default stack resolver combines multiple resolvers into a single filename, joined by a delimiter. You can
configure which resolvers are used and even apply different stacks based on URL patterns. In config/http-automock.php:
'default_filename_resolver' => 'stack', 'filename_resolvers' => [ 'stack' => [ 'resolver' => \HttpAutomock\Resolver\StackResolver::class, 'filenameResolvers' => [ // '*' matches all URLs, use specific patterns to customize per host '*' => ['count', 'http_method', 'url_hash'], ], 'delimiter' => '_', ], // Individual resolvers referenced above 'count' => \HttpAutomock\Resolver\CountResolver::class, 'http_method' => \HttpAutomock\Resolver\RequestMethodResolver::class, 'url_hash' => [ 'resolver' => \HttpAutomock\Resolver\RequestUrlResolver::class, 'hashMethod' => 'xxh32', ], 'url_subdirectory' => [ 'resolver' => \HttpAutomock\Resolver\RequestUrlResolver::class, ], 'data_hash' => [ 'resolver' => \HttpAutomock\Resolver\RequestResolver::class, 'hashMethod' => 'xxh32', ], ],
With the default stack config above, a filename like 1_GET_4c147242.mock is produced by joining
count (1), http_method (GET), and url_hash (4c147242) with _.
You can customize the stack per URL pattern. The first matching pattern wins:
'filenameResolvers' => [ '*api.example.com*' => ['http_method', 'url_subdirectory'], '*' => ['count', 'http_method', 'url_hash'], ],
File Storage
Configure where and how mock files are stored. Directory and Extension control the base path and file extension for mock files. These can be configured via CLI flags or in the published config file.
Shared Directory stores mocks in a shared location for all tests instead of per-test directories:
Http::automock()->shared();
Prettify Directory Naming cleans up test directory names by removing closure suffixes (e.g. _Closure_Object) from
Pest's directory naming:
Http::automock()->prettifyDirectoryNaming();
Headers
By default, only response bodies are saved to mock files. If your application logic depends on specific response
headers (e.g. Content-Type, X-RateLimit-Remaining), you can opt in to persisting them.
Http::automock()->withHeaders(['Server']); // Specific headers Http::automock()->withHeaders(); // All headers
Renewing / Pruning
Renew forces Automock to re-fetch responses from the real API even when mock files already exist. The new responses overwrite the existing mock files. This is useful when you know an external API has changed, and you want to update your saved mocks to reflect the current behavior.
Http::automock()->renew();
Pruning deletes all existing mock files for the executed test before running it. Only mock files belonging to that specific test are removed, not mocks from other tests. This ensures you start with a clean slate, removing any leftover mocks from requests that are no longer made by the test.
Http::automock()->prune();
Prevent Auto Renew overrides and disables renewing, pruning, and validation, regardless of their individual
settings. This is useful for CI environments where you want to ensure that no real requests are made, while still
being able to pass --automock-renew during local development without conflicts.
Http::automock()->preventAutoRenew();
Tip
It would be possible to set up a CI pipeline, that renews and commits responses periodically. Consider using some sort of request prevention on tests where it is crucial to deny.
Preventing Requests
By default, when no mock file exists for a request, Automock makes a real HTTP call and records the response. In some scenarios, especially CI pipelines or destructive operations, you want to guarantee that no real requests are ever made. Automock provides two levels of protection:
Prevent all real requests blocks every outgoing HTTP request and throws PreventedRequestException. No real
requests are made, even if mock files are missing. This is the strictest mode.
Http::automock()->preventRealRequests();
Note
Avoid setting this as a project-wide default. It prevents Automock from recording new mocks or renewing existing
ones. Consider using preventUnknownRealRequests or no prevention whenever possible.
Prevent only unknown requests is a more flexible alternative. It throws PreventedRequestException only for
requests that don't already have a mock file on disk. Requests with existing mocks still work, including when
combined with renew() or prune() to re-fetch and update them.
Http::automock()->preventUnknownRealRequests();
Note
Like preventRealRequests, avoid setting this as a project-wide default, it limits Automock's ability to record
new requests.
Tip
It is highly recommended to enable one of these options in your CI pipeline to ensure tests never make real HTTP calls unexpectedly.
Skipping Requests
Exclude certain requests from being recorded or replayed. Skipped requests pass through to their normal behavior
(real HTTP call or Laravel's Http::fake()).
Skip by URL pattern:
Http::automock()->skip('*example.com*', 'alias');
Skip by closure:
Http::automock()->skip(fn (Request $request) => str_contains($request->url(), 'skip'), 'alias');
Skip by HTTP method:
Http::automock()->skipGet(); Http::automock()->skipPost(); Http::automock()->skipPut(); Http::automock()->skipDelete(); Http::automock()->skipUnlessGet(); // Skip all except GET
Clear skip filters:
Http::automock()->stopSkip(); // Clear all Http::automock()->stopSkip('alias'); // Clear specific
Validation
When enabled, Automock makes real HTTP requests even when mock files already exist. Instead of replaying the saved response, it compares the live response against the existing mock file and fails the test if they differ. The mock files themselves are not updated. This is useful for detecting when an external API has changed its response format or data, without permanently overwriting your saved mocks. Can be prevented explicitly by enabling prevent auto-renew.
Http::automock()->validateMocks();
Mock HTTP Fakes
By default, Automock only records responses from real HTTP requests and ignores responses produced by Laravel's
Http::fake(). When this option is enabled, faked responses are also saved to mock files. This can be useful when
you want to extract inline fakes into mock files.
Http::automock()->mockHttpFakes();
JSON Pretty Print
When enabled (on by default), JSON response bodies are formatted with indentation in mock files. This makes diffs more readable in version control and makes it easier to inspect saved responses manually.
Http::automock()->jsonPrettyPrint();
Troubleshooting
Windows Git long paths
It might be recommended / essential to use Git long paths when generating long file names. To do so, execute one of the first 2 commands, then review with the 3rd.
git config --global core.longpaths true git config core.longpaths true git config --list --show-origin
For more information see here.