studio-design / openapi-contract-testing
Framework-agnostic OpenAPI 3.0/3.1 contract testing for PHPUnit with endpoint coverage tracking
Package info
github.com/studio-design/openapi-contract-testing
pkg:composer/studio-design/openapi-contract-testing
Requires
- php: ^8.2
- opis/json-schema: ^2.6
- phpunit/phpunit: ^11.0 || ^12.0 || ^13.0
- psr/http-client: ^1.0
- psr/http-factory: ^1.0
- psr/http-message: ^1.0 || ^2.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.94
- guzzlehttp/psr7: ^2.0
- orchestra/testbench: ^9.0 || ^10.0 || ^11.0
- phpstan/phpstan: ^2.1.13
- symfony/http-foundation: ^6.4 || ^7.0 || ^8.0
- symfony/yaml: ^6.4 || ^7.0 || ^8.0
Suggests
- fakerphp/faker: Improves the realism of inputs generated by ExploresOpenApiEndpoint (email, uuid, urls). The fuzzer falls back to deterministic primitives when not installed.
- guzzlehttp/guzzle: A PSR-18 HTTP client implementation for resolving external HTTP(S) $refs
- illuminate/testing: Required for the Laravel adapter (ValidatesOpenApiSchema trait)
- pestphp/pest: Activates the Pest expectation API (toMatchOpenApiResponseSchema / toMatchOpenApiRequestSchema). Library runtime stays Pest-free; the plugin auto-loads only when Pest is installed.
- symfony/http-client: A PSR-18 HTTP client implementation for resolving external HTTP(S) $refs
- symfony/yaml: Required to load OpenAPI specs directly from .yaml / .yml files
- dev-main
- v1.6.0
- v1.5.0
- v1.4.0
- v1.3.0
- v1.2.0
- v1.1.0
- v1.0.0
- v0.19.0
- v0.18.0
- v0.17.0
- v0.16.0
- v0.15.0
- v0.14.0
- v0.13.0
- v0.12.0
- v0.11.0
- v0.10.0
- v0.9.0
- v0.8.0
- v0.7.0
- v0.6.0
- v0.5.2
- v0.5.1
- v0.5.0
- v0.4.0
- v0.3.0
- v0.2.0
- v0.1.0
- dev-release-please--branches--main--components--openapi-contract-testing
- dev-feat/default-testsuite-as-full
- dev-docs/upgrading-v1.x
- dev-feat/tracker-instance-di
- dev-feat/strict-required-per-call
- dev-feat/strict-required-nested-walk
- dev-feat/strict-required-paratest-aggregation
- dev-feat/strict-required-mode
- dev-docs/issue-221-partial-run
- dev-fix/partial-run-skip-output-file
- dev-fix/ref-resolver-opaque-data
- dev-fix/empty-object-request-body
- dev-fix/issue-214-converter-recursion-gap
- dev-fix/prefix-items-sibling-items
- dev-docs/reorganize-readme-into-docs-subdir
- dev-docs/coverage-output-formats
- dev-feat/coverage-html-output
- dev-feat/coverage-json-output
- dev-feat/coverage-junit-xml
- dev-refactor/coverage-report-dispatch
- dev-refactor/php-cs-fixer-pest-override
- dev-refactor/phpstan-pest-stub
- dev-test/pest-plugin-negative-paths
- dev-chore/test-pest-defensive-guard
- dev-refactor/http-method-list-helper
- dev-ci/pest-matrix-php-84
- dev-docs/examples-pest-controller-note
- dev-docs/pest-plugin
- dev-feat/pest-plugin-expectations
- dev-feat/pest-plugin-scaffold
- dev-feat/asserts-no-enum-drift-trait
- dev-feature/issue-132-path-not-found-suggestions
- dev-renovate/configure
- dev-feat/ci-markdown-coverage-output
- dev-feat/support-php84-phpunit13
- dev-fix/ci-matrix-php82-phpunit12
This package is auto-updated.
Last update: 2026-05-13 07:51:28 UTC
README
Framework-agnostic OpenAPI 3.0/3.1 contract testing for PHPUnit with endpoint coverage tracking.
Validate your API responses against your OpenAPI specification during testing, and get a coverage report showing which endpoints have been tested.
Features
- OpenAPI 3.0 & 3.1 support — Automatic version detection from the
openapifield - Response & request validation — JSON Schema (Draft 07 via opis/json-schema) for body, parameters, and security schemes;
application/jsonand any+jsoncontent type - Endpoint coverage tracking — Unique PHPUnit extension that reports which spec endpoints are covered by tests, at
(method, path, status, content-type)granularity - Schema-driven request fuzzing —
ExploresOpenApiEndpointtrait generates N happy-path inputs straight from the spec (Schemathesis-style) - Enum drift detection — Static comparison between PHP backed enums and their
enum:spec arrays, with PHPUnit-extension auto-discovery - Schema under-description detection — Optional strict mode that flags response fields the implementation always returns but the spec marks as optional, catching the spec gaps that conformance checks alone can't. See
docs/strict-required.mdfor current scope and limitations. - Skip-by-status-code — Configurable regex list of status codes whose bodies are not validated (default: every
5xx); per-request viaskipResponseCode() - Laravel & Pest adapters — Auto-assert / auto-validate-request integration, with explicit
expect(...)->toMatchOpenApiResponseSchema()for Pest - Parallel-runner safe — Coordinated sidecar+merge workflow for paratest /
pest --parallel - Multi-format reports — Markdown / JUnit XML / JSON / HTML output with one-click GitHub Step Summary
- Zero runtime overhead — Only used in test suites
Why this library?
This library fills a gap left by existing PHP OpenAPI testing tools: endpoint coverage tracking and first-class OpenAPI 3.1 support, combined with Laravel auto-assert DX. If you already use Spectator and don't need coverage reports, this library won't offer much. If you want to see which endpoints your test suite actually exercises, or you're writing OpenAPI 3.1 specs, this is likely the best choice today.
Feature comparison (as of 2026-04)
| This library | Spectator | league/psr7 | osteel | kirschbaum | |
|---|---|---|---|---|---|
| OpenAPI 3.0 | ✅ | ✅ | ✅ | ✅ | ✅ |
| OpenAPI 3.1 | ✅ | ⚠️ | ❌ | ⚠️ | ⚠️ |
| Response body validation | ✅ | ✅ | ✅ | ✅ | ✅ |
| Request validation (body + params) | ✅ | ✅ | ✅ | ✅ | ✅ |
| Response header validation | ✅ | ⚠️ | ✅ | ✅ | ✅ |
| Endpoint coverage tracking | ✅ | ❌ | ❌ | ❌ | ❌ |
| Schema-driven request fuzzing | ✅ | ❌ | ❌ | ❌ | ❌ |
| Skip-by-status-code (default 5xx) | ✅ | ❌ | ❌ | ❌ | ✅ |
| PHPUnit integration | ✅ | ✅ | ❌ | ⚠️ | ✅ |
| Pest plugin | ✅ | ❌ | ❌ | ❌ | ❌ |
| Laravel auto-assert | ✅ | ✅ | ❌ | ❌ | ✅ |
| Symfony HttpFoundation | ❌ | ❌ | ⚠️ | ✅ | ❌ |
External $ref auto-resolution |
✅ | ✅ | ✅ | ✅ | ✅ |
| YAML spec loading | ✅ | ⚠️ | ✅ | ✅ | ✅ |
| Auto-inject dummy bearer | ✅ | ❌ | ❌ | ❌ | ❌ |
| GitHub Step Summary output | ✅ | ❌ | ❌ | ❌ | ❌ |
Legend: ✅ fully supported · ⚠️ partial, delegated to an underlying library, or not explicitly documented · ❌ not supported
Methodology: Cells reflect what each library's public documentation and source explicitly guarantee as of 2026-04-25. Competitor versions checked: Spectator v2.2.0, league/openapi-psr7-validator v0.22, osteel/openapi-httpfoundation-testing v0.14, kirschbaum-development/laravel-openapi-validator v2.0.
Requirements
- PHP 8.2+
- PHPUnit 11, 12, or 13
- A PSR-18 HTTP client + PSR-17 request factory (e.g. Guzzle, Symfony HttpClient) — only required when resolving HTTP(S)
$refs
Installation
composer require --dev studio-design/openapi-contract-testing
YAML specs require
symfony/yaml. It is listed undersuggestso it isn't installed automatically. If your spec is JSON, you can skip this. If your spec is.yaml/.yml, add it explicitly:composer require --dev symfony/yamlWithout it, the loader throws
InvalidOpenApiSpecExceptionwith a clear "requires symfony/yaml" message the first time it tries to read a YAML file.
Quick start
Three steps to your first contract-tested endpoint with the Laravel adapter. For framework-agnostic usage, configuration knobs, opt-out attributes, and request-side validation, see docs/setup.md.
1. Provide your OpenAPI spec
Point the loader at your spec's entry file. Internal and local-filesystem $ref are resolved automatically — no pre-bundling required:
openapi/
├── root.yaml # paths reference ./schemas/*.yaml
└── schemas/
├── pet.yaml
└── error.json
2. Register the PHPUnit extension
<extensions> <bootstrap class="Studio\OpenApiContractTesting\PHPUnit\OpenApiCoverageExtension"> <parameter name="spec_base_path" value="openapi/bundled"/> <parameter name="strip_prefixes" value="/api"/> <parameter name="specs" value="front,admin"/> </bootstrap> </extensions>
3. Assert in tests (Laravel)
php artisan vendor:publish --tag=openapi-contract-testing
Set default_spec in the published config/openapi-contract-testing.php, then mix in the trait:
use Studio\OpenApiContractTesting\Laravel\ValidatesOpenApiSchema; class GetPetsTest extends TestCase { use ValidatesOpenApiSchema; public function test_list_pets(): void { $response = $this->get('/api/v1/pets'); $response->assertOk(); $this->assertResponseMatchesOpenApiSchema($response); } }
To validate every response automatically, set 'auto_assert' => true and drop the explicit assert call. To also catch request-side drift, set 'auto_validate_request' => true. See docs/setup.md for the full configuration and opt-out reference.
Documentation
| Topic | Reference |
|---|---|
Full setup, framework-agnostic adapter, auto-assert, opt-out attributes, request validation, HTTP $ref |
docs/setup.md |
Pest plugin: expect()->toMatchOpenApiResponseSchema() and friends |
docs/pest-plugin.md |
| Schema-driven request fuzzing | docs/fuzzing.md |
| Enum drift detection | docs/enum-drift.md |
Schema under-description detection (strict_required) |
docs/strict-required.md |
| Coverage report modes & threshold gate | docs/coverage.md |
| HTML coverage output | docs/coverage-html-output.md |
| JSON coverage output schema | docs/coverage-json-schema.md |
Parallel test runners (paratest / Pest --parallel) |
docs/parallel.md |
| CI integration (GitHub Actions, PR comments, output formats, partial-run handling) | docs/ci.md |
API reference (OpenApiResponseValidator, OpenApiSpecLoader, OpenApiCoverageTracker) |
docs/api-reference.md |
| Supported features, known limitations, warning channel | docs/supported-features.md |
| Versioning policy & support matrix | docs/versioning.md |
Development
composer install # Run tests vendor/bin/phpunit # Static analysis vendor/bin/phpstan analyse # Code style vendor/bin/php-cs-fixer fix vendor/bin/php-cs-fixer fix --dry-run --diff # Check only
License
MIT License. See LICENSE for details.