Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Client Integration Tests Laravel Package

php-http/client-integration-tests

Integration test suite for PHP HTTP clients and adapters. Provides a shared test server and PHPUnit testsuite so you can verify that your client correctly implements the PSR-18 and HTTPlug contracts against real HTTP requests.

View on GitHub
Deep Wiki
Context7

Getting Started

Decide first whether you actually own a PSR-18 client. This package is a black-box conformance suite for people who implement or wrap a PSR-18 / HTTPlug client. If your Laravel app only calls Http::get(...) (Guzzle under the hood, already validated upstream), stop here — there is no seam for this package to plug into. It is require-dev only and has zero runtime footprint, so its entire value is in gating a client implementation you own.

You are the target audience if any of these are true:

  • You maintain an internal PSR-18 client or a wrapper around Guzzle/Symfony HttpClient (retries, auth, logging baked in).
  • You are forking or pinning an adapter and want upstream behavior changes to surface as failing tests, not production incidents.
  • You are running a formal bake-off between client libraries and want an objective, standards-anchored scorecard.

Minimal setup. It is additive and reversible:

composer require --dev php-http/client-integration-tests
composer require --dev php-http/curl-client laminas/laminas-diactoros

Start the bundled test server in a separate process:

vendor/bin/http_test_server

Then subclass the provided base test case, register a dedicated PHPUnit testsuite, and run:

./vendor/bin/phpunit --testsuite curl --printer "Http\Client\Tests\ResultPrinter"

Where to look first. Open the IntegrationTestCase (or equivalent base) you are meant to extend and locate the abstract factory methods — createClient() plus the PSR-17 factory hooks ($requestFactory / $streamFactory since 4.0.0). Those are the only two or three things you must implement; everything else is inherited. The ResultPrinter is the second stop — it is what makes failures readable instead of a wall of assertion noise.

First use case. Wrap your configured stack, not a bare client. Override the options hook so middleware (retries, logging, auth headers) is part of the system under test. A conformance suite that validates a raw client you never ship tests the wrong thing.

What this is not. It does not replace Http::fake(), Http::preventStrayRequests(), or contract tests against your own API consumers. Say that boundary out loud in the adoption RFC or the suite will get copied into application test dirs and rot there.

Implementation Patterns

Dedicated package, dedicated testsuite. Keep the conformance tests out of the default phpunit.xml run. Register a named testsuite per adapter (curl, guzzle, your internal client) matching the README's --testsuite pattern, and run it only in the CI job that owns it. Application test suites stay fast and hermetic; conformance tests stay isolated and explicitly opt-in.

Subclass once, parameterize the matrix. Create tests/Integration/<OurClient>IntegrationTest.php extending the base case. If you ship multiple transports or auth modes, drive them from a data provider or environment variables rather than copy-pasting test classes — the base case is designed around a single factory method, and duplicating subclasses is how you end up with five divergent copies of the same override.

Inject your real middleware. The high-leverage pattern: getOptions() (or the equivalent hook) returns the handler stack you actually deploy — retry policy, correlation-ID propagation, timeout defaults. This turns the suite from "does Guzzle speak PSR-18" (it does; upstream already proved it) into "does our configuration still speak PSR-18," which is the only question with nonzero answer-value for you.

Bake-off scorecard. When evaluating Guzzle vs. Symfony HttpClient vs. curl-client, run all three against the same suite and diff the pass/fail lists. Treat it as a structured comparison: which clients mishandle redirects with auth headers, which drop Content-Length on HEAD, which leak stream handles. This is the strongest day-to-day use for a Laravel team — it converts an opinion-driven library decision into evidence.

Regression gate on pinned adapters. If you pin a specific adapter version, run this suite in CI on the pinned version and on the next available minor. A behavioral diff between the two is exactly the upstream breakage you would otherwise discover in production. This is cheap insurance and the suite is the only tool in the ecosystem that gives it to you.

Offline-first CI wiring. Start http_test_server before the job, kill it in a trap/teardown, and fail hard if the port is unavailable — never let the suite silently skip. Anything that touches httpbin.org (see 3.1.1, which reverted to it) must be behind an integration group you can disable when egress is restricted, or your CI gains an availability dependency outside your control. Target 100% local-server coverage; treat external calls as a documented exception, not the default.

Async is opt-in and probably skip. Async coverage needs ext-uv / ReactPHP and HTTPlug 2.0 (optional since 3.0.0). Unless you genuinely ship an async transport, run --exclude-group async and accept the coverage reduction. Don't install a C extension to make a test suite you barely need go green.

Pin the pair. Pin the package version and the PHPUnit major together — the test classes are exactly the kind of code that breaks at runtime on a PHPUnit bump. Whenever you move Laravel's PHPUnit major, budget an upgrade task for this suite, not a "run it and see."

Gotchas and Tips

It is a network-and-process suite, not a unit test. This trips up teams who drop it into a normal test job. It needs a listening port (default 8080), a child process, and cleanup. In containerized CI that means port availability checks and teardown; in parallel test runs it means port collisions unless you read the server's bind configuration.

The 4.0.0 PSR-17 rename is a hard break. $messageFactory was deprecated and replaced by $requestFactory and $streamFactory. Any subclass written against 3.x will not work — this is a mechanical but mandatory edit before upgrading, and it is easy to miss because the error surfaces at runtime inside inherited setup, not at your override site.

PHPUnit compatibility is nominal, not guaranteed. 4.0.0 says "Allow PHPUnit > 9," which is a constraint, not a tested claim. Modern Laravel is on PHPUnit 10/11 and often Pest. Spike it — write one subclass and run it against your actual PHPUnit major before you commit to any CI wiring. If it doesn't run cleanly, that decision is "don't adopt," and you want to learn that in an hour, not after the CI job is built.

Result printer must be passed explicitly. Without --printer "Http\Client\Tests\ResultPrinter" the failure output is generic assertion spam and you will waste real time decoding which HTTP semantic actually broke. Bake it into the CI command or a Composer script so nobody has to remember it.

Some client behavior is legitimately optional. Specific relaxations exist precisely because the spec permits variation: 3.2.1 and 4.1.1 both allow a HEAD response to omit Content-Length; 0.6.2 allows Content-Length: 0 to be optional on TRACE; 1.0.0 stopped testing TRACE with request bodies because that is invalid per RFC 7231. If you see these as failures, check whether you are on a version that predates the relaxation before filing an adapter bug.

Treat the repository metrics as unverified. The dependents: 0 and a last-release date of 2026-07-05 are both data-quality flags — 0 dependents is implausible given that php-http adapters historically used this suite. Confirm the real latest tag and commit history on Packagist/GitHub before any approval or procurement decision. Do not lean on star count or dependent count as a quality proxy here.

Supply-chain posture is fine, bus factor is not. MIT, legitimate php-http organization, changelog back to 0.1.0, dev-only so it cannot reach production. The actual risk is single-organization, volunteer-driven maintenance — if your CI job depends on it and nobody owns the version pin, it becomes an orphaned flaky job within two quarters. Assign an owner or don't wire it up.

Extension points are narrow by design. Subclass factory methods and the PSR-17 factory hooks are the seams. There is no plugin system for custom assertions; if you need to test behavior outside PSR-18/PSR-7 conformance (your auth flow, your retry semantics), that belongs in your own tests, not in a fork of this suite.

Debugging failures: distinguish client bug from harness bug. Before blaming your client, confirm the test server is actually the one responding (wrong port, stale process, a leftover listener from a previous run) and that the base URL matches what the inherited test case expects. A surprising number of "failed conformance" reports are a server that never started or a suite pointed at the wrong host.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc