# Gesso
**/ˈdʒɛs.so/** —— 发音为 “JESS-so”
Gesso 是在画布上绘画前涂抹的底料——一层稳定、易于附着的基础,完成的作品在此之上构建。Gesso 将同样的理念引入到 API 中,为 PHP 中的 OpenAPI 契约测试提供可靠的基础。
[](https://github.com/studio-design/gesso/actions/workflows/ci.yml)
[](https://packagist.org/packages/studio-design/gesso)
[](https://packagist.org/packages/studio-design/gesso)
[](https://packagist.org/packages/studio-design/gesso)
[](https://packagist.org/packages/studio-design/gesso)
Gesso 为 PHPUnit 提供了与框架无关的 OpenAPI 3.0/3.1/3.2 契约测试,**支持 endpoint 覆盖率追踪**。
在测试期间,根据你的 OpenAPI 规范验证 API 响应,并获取显示已测试 endpoint 的覆盖率报告。
Gesso 2 以 `studio-design/gesso` 发布,并在 `Studio\Gesso\` 下声明其公共 PHP API。从 `studio-design/openapi-contract-testing` v1.10 升级时,请遵循[分阶段 v2 迁移指南](docs/migration/v2.md)。
**[搜索文档](https://studio-design.github.io/gesso/)** · [核心快速入门](https://studio-design.github.io/gesso/quickstarts/core) · [Laravel](https://studio-design.github.io/gesso/quickstarts/laravel) · [Symfony](https://studio-design.github.io/gesso/quickstarts/symfony) · [Pest](https://studio-design.github.io/gesso/quickstarts/pest)
## 功能
- **支持 OpenAPI 3.0、3.1 和 3.2** —— 明确的版本检测,包括 3.2 的 `QUERY`、自定义 `additionalOperations`、表单 `querystring`、`discriminator.defaultMapping` 以及可观察流的限制
- **响应和请求验证** —— 通过 opis/json-schema 实现感知方言的 JSON Schema:为 OpenAPI 3.0 提供 Draft 07 兼容性,并为 OpenAPI 3.1/3.2 提供原生的 2020-12 语义;支持 `application/json` 及任何 `+json` 内容类型
- **Endpoint 覆盖率追踪** —— 独有的 PHPUnit 扩展,以 `(method, path, status, content-type)` 的粒度报告哪些规范 endpoint 已被测试覆盖
- **Laravel 路由/规范一致性** —— `openapi:routes` 可找出缺少路由的已记录操作和缺少 OpenAPI 操作的已注册路由,支持过滤器、稳定的 JSON 输出和独立的 CI 门禁
- **基于 schema 的请求 fuzzing** —— 有效的边界、组合分支、带有明确预期状态类的定向负面测试用例、确定性的重放/缩减、全局规范过滤、生命周期/auth 钩子以及明确的跳过原因
- **Enum 漂移检测** —— 在 PHP backed enum 及其 `enum:` 规范数组之间进行静态比较,支持 PHPUnit 扩展的自动发现
- **Schema 描述不足检测** —— 可选的严格模式,标记实现总是返回但规范标记为可选的响应字段,捕获单纯的一致性检查无法发现的规范缺口。有关当前范围和限制,请参见 [`docs/strict-required.md`](docs/strict-required.md)。
- **按状态码跳过** —— 可配置的正则表达式状态码列表,不验证这些状态码的主体(默认:所有 `5xx`);可通过 `skipResponseCode()` 针对特定请求设置
- **PSR-7、Laravel、Symfony 和 Pest 适配器** —— 一流的 PSR-7 请求/响应/交换验证,为 Laravel 提供 auto-assert / auto-validate-request 集成,为 Symfony 提供 HttpFoundation 断言,以及 Pest 期望
- **支持并行运行器** —— 为 paratest / `pest --parallel` 协调 sidecar+合并工作流
- **多格式报告** —— Markdown / JUnit XML / JSON / HTML 输出,支持一键 GitHub Step Summary
- **零运行时开销** —— 仅用于测试套件
## 为什么选择这个库?
根据您所需的工作流程进行选择,而不是仅基于单一的“是/否”功能数量:
- 当您需要 `(method, path, status, content-type)` 粒度的响应级覆盖率、多种 CI 报告格式、OpenAPI 3.1/3.2 JSON Schema 语义、基于 schema 的探索,或在与框架无关的核心以及 Laravel、Symfony 和 Pest 适配器之间进行漂移检测时,请选择**此库**。
- 对于 Laravel 12 应用,当生成的测试 stub、JSON 断言失败或远程/私有 GitHub 规范来源比响应级覆盖率的粒度和更广泛的框架支持更重要时,请选择 **[Spectator][spectator]**。
- 当您想要一个低级别的 PSR-7 验证器或 PSR-15 中间件,并打算自行构建测试/报告集成时,请选择 **[league/openapi-psr7-validator][league]**。
- 当您想要一个小型的 HttpFoundation 到 PSR-7 的验证桥接时,请选择 **[osteel/openapi-httpfoundation-testing][osteel]**;或者当主要需求是在 Laravel HTTP 测试周围进行自动验证时,请选择 **[laravel-openapi-validator][kirschbaum]**。
### 功能对比(检查日期 2026-07-10)
| 功能 | **此库** | [Spectator v3.0.2][spectator] | [league/psr7 v0.24][league] | [osteel v0.14][osteel] | [kirschbaum v2.0.2][kirschbaum] |
| --- | --- | --- | --- | --- | --- |
| 明确支持的 OpenAPI 版本 | [3.0, 3.1, 3.2](docs/supported-features.md) | 未说明版本范围 | [3.0.x][league-readme] | [3+;委托给 League v0.22][osteel-composer] | [委托给 League v0.14–0.24][kirschbaum-composer] |
| 请求 + 响应验证 | ✅ | [✅ Laravel][spectator] | [✅ PSR-7][league-readme] | [✅ HttpFoundation / PSR-7][osteel-readme] | [✅ Laravel HTTP tests][kirschbaum-readme] |
| 覆盖率粒度 | [`method, path, status, content-type`](docs/coverage.md) | [`method, path` operation][spectator-coverage-source] | — | — | — |
| 覆盖率输出 | [Markdown, JUnit XML, JSON, HTML, GitHub Step Summary](docs/coverage.md) | [Text, JSON][spectator-coverage] | — | — | — |
| 并行覆盖率合并 | [Sidecar + merge CLI](docs/parallel.md) | 未记录 | — | — | — |
| 路由/规范一致性 | [`openapi:routes`](docs/laravel-route-parity.md) 支持 text/JSON 和 CI 门禁 | [`spectator:routes`][spectator-cli] | — | — | — |
| CLI 诊断 / 脚手架 | [`doctor`](docs/doctor.md), [`openapi:routes`](docs/laravel-route-parity.md), 覆盖率合并;无脚手架 | [`validate`, `coverage`, `routes`, `stubs`][spectator-cli] | — | — | — |
| 结构化验证失败 | 文本消息;计划支持 JSON ([#282](https://github.com/studio-design/gesso/issues/282)) | [JSON `{errors: [...]}`][spectator-errors] | [PHP exception hierarchy][league-errors] | [Wrapper exception][osteel-readme] | [PHPUnit failure text][kirschbaum-failure-source] |
| 基于 schema 的探索 | [确定性 endpoint + 全局规范生成](docs/fuzzing.md) | — | — | — | — |
| 漂移 / 描述不足检查 | [Enum drift](docs/enum-drift.md), [strict required](docs/strict-required.md) | — | — | — | — |
| 一流集成 | [PSR-7](docs/psr7.md), [Laravel, Symfony, Pest](docs/setup.md) | [Laravel][spectator] | [PSR-7, PSR-15 middleware][league-middleware] | [HttpFoundation, PSR-7][osteel-readme] | [Laravel auto-validation][kirschbaum-readme] |
| 声明的运行时最低要求 | PHP 8.3 核心;[Testbench 9–11](composer.json) ([Laravel 11–12][testbench-compat]; [Laravel 13 / PHP 8.3][testbench-11-composer]) | [PHP 8.3, Laravel 12][spectator-composer] | [PHP 7.2][league-composer] | [PHP 8.0, HttpFoundation 5–8][osteel-composer] | [PHP 8.0, Illuminate 10–13][kirschbaum-composer] |
**图例**:✅ 支持 · — 未记录有等效功能。“未记录”与“不支持”有本质区别。
**方法论**:这是一次文档/来源审计,不是基准测试。声明仅限于链接的、标签固定的公开文档以及在 2026-07-10 检查的 Composer 约束。此库的声明描述了位于 [`8c6416d` 的 `main` 分支](https://github.com/studio-design/gesso/commit/8c6416dcd7edf179010f5f1cdc71a1e146a5c403);竞争对手的版本显示在表头中。当过去三个月或有新版本发布时,至少每季度使用[发布检查清单](docs/versioning.md#release-checklist)重新检查此矩阵。
## 要求
- PHP 8.3+
- PHPUnit 12 或 13
- PSR-18 HTTP 客户端 + PSR-17 请求工厂(例如 Guzzle, Symfony HttpClient)——仅在解析 HTTP(S) `$ref` 时需要
## 安装
```
composer require --dev "studio-design/gesso:^2.0"
```
## 快速开始
选择与您的技术栈相匹配且经过 CI 测试的五分钟路径:
| 技术栈 | 通过的示例 | 展示内容 |
| --- | --- | --- |
| 与框架无关的 PHPUnit | [`examples/core`](examples/core) | 直接响应验证和覆盖率 |
| Laravel | [`examples/laravel`](examples/laravel) | 显式断言、`auto_assert` 和请求验证 |
| Symfony | [`examples/symfony`](examples/symfony) | HttpFoundation 请求/响应断言 |
| Pest | [`examples/pest`](examples/pest) | Laravel 响应和请求期望 |
| PSR-7 | [`examples/psr7`](examples/psr7) | 请求/响应交换验证 |
所有路径均从相同的开发依赖开始:
```
composer require --dev "studio-design/gesso:^2.0"
```
下面的示例使用 PSR-7 请求和响应。可搜索的文档包含完整的[核心](https://studio-design.github.io/gesso/quickstarts/core)、[Laravel](https://studio-design.github.io/gesso/quickstarts/laravel)、[Symfony](https://studio-design.github.io/gesso/quickstarts/symfony) 和 [Pest](https://studio-design.github.io/gesso/quickstarts/pest) 快速入门指南。
### 1. 提供您的 OpenAPI 规范
将加载器指向您的规范的入口文件。内部和本地文件系统的 `$ref` 会自动解析——无需预先打包:
```
openapi/
├── root.yaml # paths reference ./schemas/*.yaml
└── schemas/
├── pet.yaml
└── error.json
```
### 2. 注册 PHPUnit 扩展
在运行第一个测试之前,验证该包是否可以加载并执行契约:
```
vendor/bin/gesso doctor \
--spec=openapi/root.yaml \
--strip-prefix=/api \
--phpunit-snippet
```
该命令会解析本地引用,检查 OpenAPI/JSON Schema 方言,报告不受支持的执行功能,计算发现的操作和响应,并对不兼容的规范返回非零退出码。在 CI 中使用 `--format=json`。有关多规范、HTTP 引用、输出类别和退出码的信息,请参见 [doctor 命令参考](docs/doctor.md)。
然后注册输出的配置:
```
```
### 3. 验证 PSR-7 交换
当您的应用程序或 HTTP 客户端已经返回 PSR-7 消息时,通过一个独立于框架的调用来验证双方并记录覆盖率:
```
use Studio\Gesso\Psr7\OpenApiPsr7Validator;
$validator = new OpenApiPsr7Validator('front');
$result = $validator->validateExchange($request, $response);
$this->assertTrue($result->isValid(), $result->errorMessage());
```
适配器接受任何 `psr/http-message` 实现;不会将具体的 PSR-7 包添加到生产依赖中。PHPUnit 断言 trait、仅响应的操作寻址、PSR-15 测试方案和流保证在 [PSR-7 指南](docs/psr7.md) 中有所涵盖。
### Laravel 适配器
```
php artisan vendor:publish --tag=gesso
```
在已发布的 `config/gesso.php` 中设置 `default_spec`,然后引入该 trait:
```
use Studio\Gesso\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);
}
}
```
在运行测试之前,将 Laravel 注册的路由与规范进行比较:
```
php artisan openapi:routes --fail-on-undocumented --fail-on-unimplemented
```
要自动验证每个响应,请设置 `'auto_assert' => true` 并删除显式的 assert 调用。若要同时捕获请求端的漂移,请设置 `'auto_validate_request' => true`。有关完整配置和退出机制的参考,参见 [`docs/setup.md`](docs/setup.md)。
## 文档
| 主题 | 参考 |
|---|---|
| PSR-7 请求 / 响应 / 交换验证和 PSR-15 测试方案 | [`docs/psr7.md`](docs/psr7.md) |
| 完整设置,Laravel / Symfony / 与框架无关的适配器,auto-assert,退出属性,请求验证,HTTP `$ref` | [`docs/setup.md`](docs/setup.md) |
| 测试前兼容性诊断 (`gesso doctor`) | [`docs/doctor.md`](docs/doctor.md) |
| Laravel 路由/规范一致性 (`openapi:routes`) | [`docs/laravel-route-parity.md`](docs/laravel-route-parity.md) |
| Pest 插件:`expect()->toMatchOpenApiResponseSchema()` 及相关方法 | [`docs/pest-plugin.md`](docs/pest-plugin.md) |
| 基于 schema 的请求 fuzzing | [`docs/fuzzing.md`](docs/fuzzing.md) |
| Enum 漂移检测 | [`docs/enum-drift.md`](docs/enum-drift.md) |
| Schema 描述不足检测 (`strict_required`) | [`docs/strict-required.md`](docs/strict-required.md) |
| 覆盖率报告模式和阈值门禁 | [`docs/coverage.md`](docs/coverage.md) |
| HTML 覆盖率输出 | [`docs/coverage-html-output.md`](docs/coverage-html-output.md) |
| JSON 覆盖率输出 schema | [`docs/coverage-json-schema.md`](docs/coverage-json-schema.md) |
| 并行测试运行器 (paratest / Pest `--parallel`) | [`docs/parallel.md`](docs/parallel.md) |
| CI 集成(GitHub Actions、PR 评论、输出格式、部分运行处理) | [`docs/ci.md`](docs/ci.md) |
| API 参考 (`OpenApiResponseValidator`, `OpenApiSpecLoader`, `OpenApiCoverageTracker`) | [`docs/api-reference.md`](docs/api-reference.md) |
| 支持的功能、已知限制、警告通道 | [`docs/supported-features.md`](docs/supported-features.md) |
| 版本控制策略与支持矩阵 | [`docs/versioning.md`](docs/versioning.md) |
## 开发
```
composer install
# 运行测试
vendor/bin/phpunit
# 静态分析
vendor/bin/phpstan analyse
# 代码风格
vendor/bin/php-cs-fixer fix
vendor/bin/php-cs-fixer fix --dry-run --diff # Check only
```
## 许可证
MIT 许可证。详情请参见 [LICENSE](LICENSE)。