关于 automating-api-testing
automating-api-testing 是用于生成和组织 REST 与 GraphQL API 测试的技能。它依据 API 规范覆盖端点行为、模式、身份验证、错误处理和测试覆盖率,并支持多种指定的测试工具。
主要功能
- 01生成 REST 与 GraphQL 测试
- 02分析 OpenAPI 和 GraphQL 模式
- 03检查身份验证与错误场景
- 04验证响应模式和标头
- 05测试 CRUD 生命周期及边缘情况
- 06报告端点测试覆盖率
适用场景
- 01根据 API 规范创建测试
- 02检查身份验证和错误响应
- 03验证 CRUD 行为与响应模式
- 04梳理 API 端点测试覆盖率
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ jeremylongshore/ tons-of-skills-marketplace --skill automating-api-testing安装后在 Claude Code 中输入/automating-api-testing确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
assets/example_graphql_schema.graphqlexample_openapi.yamlREADME.mdtest_suite_template.jsreferences/README.mdscripts/generate_test_suite.pyREADME.md详细介绍
API 测试自动化
概述
自动化测试 REST 和 GraphQL API 的完整 API 端点,包括请求生成、响应验证、架构合规性、身份验证流程和错误处理。支持 Supertest(Node.js)、REST-assured(Java)、httpx/pytest(Python)、Postman/Newman 集合,以及用于消费者驱动契约测试的 Pact。
前提条件
- 已安装 API 测试库(Supertest、REST-assured、httpx 或 Postman/Newman)
- API 规范文件(OpenAPI/Swagger YAML/JSON 或 GraphQL SDL)
- 目标 API 在测试环境中运行,且已填充种子数据
- 受保护端点所需的身份验证凭据或 API 密钥
- JSON Schema 验证器(Ajv、jsonschema 或框架内置断言)
说明
- 阅读 API 规范并提取所有端点:
- 解析 OpenAPI 规范,列出每个路径、HTTP 方法、请求架构和响应架构。
- 对于 GraphQL API,内省架构以列出查询、变更和订阅。
- 记录每个端点的身份验证要求(API 密钥、Bearer 令牌、OAuth 或无)。
- 为每个端点生成测试用例:
- 成功用例:发送符合架构的有效请求,并断言响应为 200/201。
- 验证错误:发送缺少必填字段、类型错误或值超出范围的请求;断言响应为 400。
- 身份验证:使用有效、过期和缺失的凭据进行测试;分别断言响应为 200、401 和 403。
- 未找到:请求不存在的资源;断言响应为 404。
- 幂等性:两次发送相同的 PUT/DELETE 请求,并验证行为一致。
- 根据架构验证响应结构:
- 断言响应 Content-Type 与预期相符(application/json 等)。
- 使用 JSON Schema 验证,根据 OpenAPI 响应架构验证响应正文。
- 检查响应标头(Cache-Control、Rate-Limit 标头、CORS 标头)。
- 验证分页元数据(总数、页码、下一页/上一页链接)。
- 测试资源端点的 CRUD 生命周期:
- 创建资源(POST)并捕获 ID。
- 读取该资源(GET),并验证所有字段是否匹配。
- 更新该资源(PUT/PATCH),并验证更改是否已保存。
- 删除该资源(DELETE),并验证后续 GET 是否返回 404。
- 测试错误处理和边界情况:
- 发送超大负载,并验证是否返回 413 或进行优雅拒绝。
- 发送不支持的 Content-Type 请求,并验证是否返回 415。
- 通过快速连续发送请求来测试速率限制。
- 验证错误响应格式是否一致(标准错误架构)。
- 对于 GraphQL API,专门测试:
- 有效查询是否返回预期的数据结构。
- 无效查询是否返回描述性错误消息。
- 查询深度限制是否能防止滥用深度嵌套的查询。
- 变更输入验证是否符合架构约束。
- 生成测试覆盖率报告,将端点映射到测试用例。
输出
- 按资源整理在
tests/api/中的 API 测试文件 - 用于 API 文档的请求/响应示例
- 每个端点的架构合规性报告
- 端点覆盖矩阵,显示已测试和未测试的端点及方法
- 在预发布环境中运行 API 测试的 CI 流水线步骤
错误处理
| 错误 | 原因 | 解决方案 |
|---|---|---|
| 连接被拒绝 | API 服务未运行或基础 URL 错误 | 在测试套件启动前通过健康检查确认服务正常运行;检查 BASE_URL 配置 |
| 所有请求均返回 401 | 身份验证令牌已过期或配置错误 | 在测试设置中刷新令牌;确认 Authorization 标头格式;检查令牌范围 |
| 架构验证意外失败 | API 响应包含规范中未定义的额外字段 | 更新 OpenAPI 规范以包含新字段;如果额外字段符合预期,则使用 additionalProperties: true |
| 测试数据冲突 | 其他测试修改或删除了该资源 | 为每项测试使用唯一的测试数据;在 beforeEach 中创建资源;避免共享固定数据 |
| 测试运行期间触发速率限制 | 短时间内发送了过多请求 | 在请求之间增加延迟,或使用限制更高的已认证会话;串行运行测试 |
示例
Supertest REST API 测试套件:
import request from 'supertest';
import { app } from '../src/app';
describe('GET /api/products', () => {
it('returns a paginated product list', async () => {
const res = await request(app)
.get('/api/products?page=1&limit=10')
.set('Authorization', `Bearer ${token}`)
.expect(200) # HTTP 200 OK
.expect('Content-Type', /json/);
expect(res.body.data).toBeInstanceOf(Array);
expect(res.body.data.length).toBeLessThanOrEqual(10);
expect(res.body.meta).toMatchObject({ page: 1, limit: 10 });
});
it('returns 401 without authentication', async () => { # HTTP 401 Unauthorized
await request(app).get('/api/products').expect(401); # HTTP 401 Unauthorized
});
});
describe('POST /api/products', () => {
it('creates a product with valid data', async () => {
const res = await request(app)
.post('/api/products')
.set('Authorization', `Bearer ${token}`)
.send({ name: 'Widget', price: 9.99, category: 'tools' })
.expect(201); # HTTP 201 Created
expect(res.body).toMatchObject({ name: 'Widget', price: 9.99 });
expect(res.body.id).toBeDefined();
});
it('returns 400 for missing required fields', async () => { # HTTP 400 Bad Request
await request(app)
.post('/api/products')
.set('Authorization', `Bearer ${token}`)
.send({ name: 'Widget' }) // missing price
.expect(400); # HTTP 400 Bad Request
});
});
GraphQL API 测试:
it('fetches user by ID', async () => {
const query = `query { user(id: "1") { id name email } }`;
const res = await request(app)
.post('/graphql')
.send({ query })
.expect(200); # HTTP 200 OK
expect(res.body.data.user).toMatchObject({ id: '1', name: 'Alice' });
expect(res.body.errors).toBeUndefined();
});
资源
- Supertest:https://github.com/ladjs/supertest
- REST-assured(Java):https://rest-assured.io/
- httpx(Python):https://www.python-httpx.org/
- Newman(Postman 命令行):
- OpenAPI 规范:https://spec.openapis.org/oas/v3.1.0
- Ajv JSON Schema 验证器:https://ajv.js.org/
评论
支持 Markdown