REST/GraphQL/gRPC 测试

共 20 题
📑 题目列表 20 题
#
★★★

1. REST API 测试的核心验证点,状态码、响应体结构、Header、错误处理的系统化测试策略?

REST API 测试的核心验证点包括状态码、响应体结构、Header 和错误处理,请给出系统化的测试策略?

  • 状态码语义与业务场景的对应(2xx/4xx/5xx)
  • 响应体结构、字段类型与约束的验证
  • Header 的验证(Content-Type、Cache-Control、自定义头等)

系统化 REST API 测试应从四个维度分层验证。一是状态码:按请求语义断言正确状态码,如 GET 成功返回 200、POST 创建返回 201、删除返回 204、参数错误返回 400、未认证返回 401、无权限返回 403、不存在返回 404、冲突返回 409、服务端异常返回 500,并验证错误码与业务场景一一对应。二是响应体结构:用 JSON Schema 校验字段的存在性、类型、必填、nullable 与枚举取值范围,并验证数据边界(空数组、超长字段、null 值)。三是 Header:验证 Content-Type、Cache-Control、ETag、Location、Retry-After、分页头等,尤其关注响应头与应用语义(如可缓存性)的一致性。四是错误处理:验证错误响应体格式统一(含 error code、message、details、trace id),能够区分客户端错误与服务端错误,且错误信息不泄露内部堆栈。实践上应构建断言分层框架,把"状态码—结构—数据—Header"作为独立断言层,配合属性驱动测试与边界值,形成可复用的契约基座。

状态码反映 HTTP 语义,结构反映数据契约,Header 反映传输与缓存语义,错误处理反映可诊断性。四者单独验证会遗漏交叉问题,因此需要系统化分层而非零散断言。统一错误格式与 trace id 是生产可观测性的关键,也是测试应主动验证的隐式契约。

// REST Assured 分层断言示例
given().baseUri("https://api.example.com")
    .header("Authorization", "Bearer " + token)
    .param("page", 1)
    .when().get("/users")
    .then()
    .statusCode(200)                                // 状态码
    .header("Content-Type", containsString("application/json"))
    .body("data", hasSize(20))                      // 结构
    .body("code", equalTo(0))                       // 业务码
    .body("data[0].name", notNullValue())           // 字段约束
    .body("meta.traceId", not(empty()));            // 可诊断性
#
★★★

2. GraphQL 测试的特殊挑战,查询复杂度、N+1 问题、类型系统的测试方法?

GraphQL 测试有哪些特殊挑战?如何针对查询复杂度、N+1 问题和类型系统设计测试方法?

  • 查询复杂度(深度、宽度、别名)与恶意查询防护
  • N+1 查询问题与加载器(DataLoader)的验证
  • 类型系统(Schema)与类型安全的测试

GraphQL 只有一个端点,通过 POST 携带 query 与 variables,响应结构由查询决定,因此测试不能像 REST 那样按 URL 组织,而应围绕"查询 + 变量"的用例设计。查询复杂度方面,需验证深度限制(maximum depth)、复杂性限制(complexity score)与别名/批量滥用防护,构造深度嵌套、别名爆炸、重复字段的恶意查询,确认服务端在达到阈值时返回 400 或错误而不会导致资源耗尽。N+1 问题方面,通过查询包含一对多嵌套关系(如 orders 内嵌 items),用 DataLoader 或 DB 查询日志断言实际 SQL 数不随嵌套数量线性增长,即验证批处理与防抖机制生效。类型系统方面,利用 GraphQL introspection 验证 schema 与类型定义一致,用 GraphQL 的类型校验(对错误类型/缺失字段返回 validation error)验证查询在进入 resolver 前就被拒绝,并可用 schema 测试工具(如 Jest 的 graphql-tools)做类型断言。总体策略是"正确性测试 + 性能/复杂度测试 + 安全测试"三线并行。

GraphQL 的查询结构由客户端灵活声明,使攻击面从 URL 转移到查询本身,因此复杂度与深度限制是安全测试的重点。N+1 是性能问题的典型来源,断言数据库查询次数而非仅看响应时间更可靠。类型系统校验发生在执行前,能提前拦截错误,是低成本高收益的测试点。

// 验证类型错误在执行前被拦截(graphql-tools)
const { validate, parse } = require('graphql');
const query = `{ user { id name unknownField } }`;
const errors = validate(schema, parse(query));
expect(errors.length).toBeGreaterThan(0); // 未知字段应在执行前被拒绝
#
★★★

3. gRPC 接口测试的四种调用方式(unary/server streaming/client streaming/bidi)各自的测试策略?

gRPC 有四种调用方式(unary、server streaming、client streaming、bidi streaming),各自的测试策略是什么?

  • 四种 RPC 模式的定义与语义
  • 每种模式的请求/响应流与超时/取消处理
  • 流式场景下的顺序、边界与中断测试

四种调用方式测试策略如下。Unary(一元):类似 REST 请求-响应,测试重点是参数校验、状态码(OK/INVALID_ARGUMENT/DEADLINE_EXCEEDED)、元数据(metadata)与超时,可用专门的测试客户端做单次调用断言。Server streaming(服务端流式):客户端发送一个请求,服务端持续返回多个消息,测试需验证消息的数量、顺序、到达间隔与最终的状态(如流结束标志),并测试客户端取消(cancel)后服务端是否停止发送,以及超时截断。Client streaming(客户端流式):客户端连续发送多个请求,服务端最后返回一个响应,测试需验证客户端按序发送、流结束(half-close)后服务端才返回响应、以及中途取消与部分数据场景。Bidi streaming(双向流式):双方同时发送,测试最复杂,需关注消息顺序、关联性、背压(backpressure)、并发读写与错误中断后的恢复。不论哪种模式,都要覆盖正常流、错误流、超时、取消与元数据传播,并利用 gRPC 的反射服务或固定 protobuf 生成客户端做自动化测试。

流式模式的时序与状态机比 unary 复杂,错误可能发生在流的任意阶段,因此测试要覆盖"流生命周期"而不仅是单个消息。取消与超时是流式协议易被忽略但极关键的边界。测试重心应放在消息顺序、完整性、背压与中断处理上。

#
★★★

4. REST API 的鉴权测试矩阵,JWT/API Key/OAuth2 的过期、刷新、越权与并发用例设计

REST API 的鉴权测试矩阵如何设计?请针对 JWT、API Key、OAuth2 设计过期、刷新、越权与并发用例?

  • 三种鉴权机制的核心差异
  • 过期、刷新、越权、并发四类场景的用例设计
  • 鉴权失败的语义(401 vs 403)与安全边界

鉴权测试矩阵以"机制 × 场景"交叉组织。JWT:验证 token 过期(过期后返回 401)、刷新(refresh token 换取新 access token、refresh 旋转与重用检测)、越权(用户 A 的 token 访问用户 B 的资源返回 403,验证 claim 中的 scope/role 被正确校验)、并发(同一 access token 的并发请求、refresh 与 access 并发时的一致性)。API Key:验证 key 过期/失效、key 权限范围(限制到特定资源)、多 key 并发配额、key 轮换与吊销。OAuth2:验证授权码流程、access token 与 refresh token 生命周期、scope 最小化、client 凭据、PKCE 与并发的 token 刷新竞态。所有机制的共同用例包括:缺失/错误/过期凭据返回 401,越权返回 403,并验证 401 与 403 语义不混淆;验证 token 在服务端被正确解析、签名与过期校验;并发场景下验证刷新 token 的幂等与防重放。

鉴权矩阵把机制与场景作笛卡尔积,能系统覆盖过期、刷新、越权、并发四类高风险点。401 与 403 的区分是语义正确性的核心,越权测试(水平越权与垂直越权)是安全测试的关键。并发刷新与重放是 OAuth2/JWT 的常见竞态缺陷,必须有专项用例。

// 鉴权测试矩阵用例描述
{
  "JWT": [
    {"用例": "过期token请求", "期望": "401"},
    {"用例": "refresh token 重放", "期望": "拒绝/旋转"},
    {"用例": "用户A越权访问用户B", "期望": "403"},
    {"用例": "并发刷新同一access", "期望": "仅一个生效"}
  ],
  "API Key": [
    {"用例": "key过期", "期望": "401"},
    {"用例": "key越权访问未授权资源", "期望": "403"}
  ],
  "OAuth2": [
    {"用例": "scope不足", "期望": "403"},
    {"用例": "PKCE验证失败", "期望": "401"}
  ]
}
#
★★

5. gRPC 接口测试的工具和方法,grpcurl/gRPC UI/编程式测试的适用场景?

gRPC 接口测试有哪些工具和方法?grpcurl、gRPC UI 与编程式测试各自的适用场景是什么?

  • grpcurl 的命令行测试场景
  • gRPC UI 的交互式调试场景
  • 编程式测试(测试框架)的场景

gRPC 测试工具按场景分为三类。grpcurl 是命令行工具,适用场景是快速冒烟测试、脚本化与 CI 中的简单调用,通过反射服务或导入 proto 文件即可调用,适合验证某个方法是否可用、返回是否正常,但不适合复杂断言与流水线编排。gRPC UI(如 grpcui、Postman 的 gRPC 支持)提供图形化界面,适用场景是交互式调试、人工浏览 service 与 message 结构、演示与探索,适合开发阶段快速验证,但难以自动化。编程式测试(如用 gRPC-Java、grpc-java 测试框架、Python 的 grpcio、以及基于反射的测试库)适用场景是自动化测试、复杂断言、负载测试与 CI 集成,能生成客户端、校验 metadata、覆盖超时/取消/流式等场景,是生产级测试的主力。选型原则:人工探索用 gRPC UI,快速验证用 grpcurl,自动化与回归用编程式测试,三者可结合。

工具选择取决于测试目的。grpcurl/gRPC UI 满足"快速试探"与"人工查看",编程式测试满足"可重复、可断言、可集成"。反射服务(reflection)让 grpcurl/gRPC UI 无需 proto 文件即可发现服务,是两者的前提条件。

#
★★

6. API 测试自动化框架选型,Postman/Newman、REST Assured、Karate 的对比?

API 测试自动化框架如何选型?请对比 Postman/Newman、REST Assured 与 Karate?

  • 各框架的定位与适用技术栈
  • 断言能力、可读性、集成与 CI 支持
  • 选型依据(团队、语言、复杂度)

Postman/Newman:Postman 是图形化请求工具,Newman 是其命令行运行器,适合非开发人员快速构建集合、做冒烟测试与调试,支持环境变量、数据文件与 CI 中运行 Newman 命令,但复杂的编程断言与大型套件维护较弱。REST Assured:Java 生态的 BDD 风格 DSL,适合 Java 后端团队的 REST 测试,断言流畅、可读性好,与 JUnit/TestNG、Spring 集成紧密,适合作为项目内的单元级/集成级 API 测试。Karate:基于 BDD 的 DSL,兼顾 API 测试、UI 测试与性能测试,无需编写 Java 代码即可表达请求与断言,支持 GraphQL、gRPC 与数据驱动,适合中大型团队快速落地统一测试。对比维度:语言亲和性(Java 团队选 REST Assured/Karate,非 Java 或快速验证选 Postman)、自动化程度(CI 集成选 REST Assured/Karate)、断言复杂度(复杂逻辑选编程式框架)、团队技能(非开发选 Postman)。选型应结合团队技术栈、维护成本与 CI 集成需求。

框架选型本质是"可维护性、可读性、团队技能"的权衡。Postman 适合快速原型与人工验证,REST Assured 适合 Java 深度集成,Karate 适合跨技术栈的统一 BDD 方案。选择一个团队能长期维护、与 CI 深度集成的框架,比追求功能齐全更重要。

#
★★

7. GraphQL 测试中如何针对"查询深度"与"N+1 查询"设计专项用例?

GraphQL 测试中如何针对"查询深度"与"N+1 查询"设计专项用例?

  • 查询深度限制与基础上限的用例
  • N+1 查询的检测与验证
  • 恶意/异常查询的边界用例

查询深度方面,设计用例:构造深度等于限制值的合法查询(应通过)、深度恰好超过限制的查询(应被拒绝,返回 400 或错误)、深度嵌套的别名链测试、以及无数层递归类型(如 self-referencing 类型)的极端深度查询,验证服务端在深度限制处正确截断而非耗尽资源;同时验证深度限制可配置且对不同客户端是否一致。N+1 查询方面,设计用例:构造包含一对多关系的查询(如 users 下取每个 user 的 posts),通过数据库查询日志、DataLoader 命中统计或服务端埋点,断言执行该查询的数据库查询次数等于"固定值"而非"随结果数量线性增长";再验证 DataLoader 的批处理与缓存(cache)在相同 id 重复请求时生效;还可用并发查询验证 DataLoader 的请求合并。专项用例通常结合性能基准(如查询前后耗时与 SQL 数对比)来量化 N+1 是否被消除。

深度用例验证防护机制是否生效,N+1 用例验证数据加载层的性能优化。两者都需了解内部实现(深度限制配置、DataLoader/日志)才能断言准确效果,因此是"白盒感知"的专项用例,而非单纯黑盒测试。

#
★★

8. WebSocket/SSE 实时接口的自动化测试如何做时间维度断言(顺序、延迟、重连)?

WebSocket/SSE 实时接口的自动化测试如何做时间维度断言(顺序、延迟、重连)?

  • 消息顺序与时间戳的断言
  • 延迟与超时阈值的断言
  • 断线重连与心跳的验证

实时接口的时间维度断言需处理异步时序。顺序断言:为每个消息记录序号或时间戳,断言接收顺序与发送顺序一致(尤其对 SSE 事件);可使用有界队列收集消息并按序比对。延迟断言:对心跳、事件推送设置期望时延阈值,断言消息到达时间(如收到心跳间隔 ≤ 阈值、首帧延迟),用 Stopwatch 记录时间并断言在合理区间,避免对绝对时间硬编码。重连断言:模拟断线(关闭 socket、网络中断),断言客户端自动重连、重连后恢复接收、心跳继续、未丢失消息,并验证指数退避重试策略(重连间隔递增)。此外要验证超时场景:服务端超时关闭、客户端超时触发重连、以及消息乱序(SSE 的 event id 与 retry 字段)处理。自动化测试需用轮询式等待机制(如 Awaitility)而非固定 sleep,确保时序断言稳定。

实时接口的异步性质使时间断言难以用同步断言表达,需引入等待库、事件驱动与时间戳记录。顺序、延迟、重连是三个相互独立又相扣的维度,且重连是实时接口高可用性的关键,需专门模拟断线场景。弹性等待(polling)与阈值而非固定时间,是时序测试稳定性的关键。

// Awaitility 等待重连成功
await().atMost(10, SECONDS)
    .untilAsserted(() -> {
        assertThat(wsClient.isConnected()).isTrue();
        assertThat(wsClient.getLastMessage().getTimestamp())
            .isCloseTo(System.currentTimeMillis(), within(2000));
    });
#
★★

9. GraphQL 的安全测试,权限绕过、批量查询、introspection 泄露与深度限制的验证方法

GraphQL 的安全测试如何验证权限绕过、批量查询、introspection 泄露与深度限制?

  • 权限绕过与越权访问的用例
  • 批量查询(alias)与资源滥用
  • introspection 泄露与深度限制

权限绕过:构造未授权查询访问受保护字段/类型,验证返回 permission denied 而非数据;测试不同角色(匿名、普通用户、管理员)对同一查询的差异,验证字段级授权(field-level authorization)是否生效,防止通过嵌套查询绕过根级权限。批量查询:利用 GraphQL 别名(alias)构造大量重复字段或并发查询,验证服务端有复杂度限制、速率限制或并发限制,防止一次性请求消耗大量资源;测试 alias 爆炸(同一字段多别名)与深度嵌套组合。introspection 泄露:在非开发环境验证 introspection 是否被禁用或需认证,测试 /graphql 端点的 __schema、__type 查询是否返回敏感 schema 信息,尤其确认生产环境不暴露内部 schema。深度限制:构造超深查询、自引用类型递归、循环引用,确认深度限制与复杂度限制生效,返回错误而非资源耗尽。综合策略是"最小权限 + 深度/复杂度限制 + introspection 管控 + 速率限制"四者联动验证。

GraphQL 单一端点使攻击面集中在查询本身,因此安全测试必须覆盖 query 层面的攻击向量。权限绕过关注授权模型,批量查询与深度限制关注资源滥用,introspection 泄露关注信息暴露。这些是生产环境 GraphQL 服务的安全基线,需系统化验证。

#
★★

10. gRPC 健康检查协议(grpc.health.v1)与反射服务在测试框架中的应用

gRPC 的健康检查协议(grpc.health.v1)与反射服务在测试框架中如何应用?

  • 健康检查协议(grpc.health.v1)的语义
  • 反射服务(reflection)的作用
  • 二者在测试框架自动化中的应用

grpc.health.v1 是 gRPC 官方健康检查协议,提供 Check 与 Watch 方法,返回服务的健康状态(SERVING、NOT_SERVING、UNKNOWN、SERVICE_UNKNOWN),测试框架用它做服务就绪探测(readiness probe)与存活检测(liveness probe),在 CI 中等待服务就绪后再执行测试,也可在健壮性测试中模拟服务进入 NOT_SERVING 状态验证客户端降级。反射服务(reflection)提供 ServerReflectionInfo,让客户端无需 proto 文件即可动态发现服务、方法与消息结构,测试框架利用反射动态生成请求、验证服务端是否暴露预期接口,并且 grpcurl/gRPC UI 等工具依赖反射实现免 proto 调用。测试框架结合二者:用健康检查做依赖就绪门控,用反射做动态契约发现与接口一致性验证,减少 proto 文件维护成本,提升测试通用性。

健康检查是分布式测试中的"就绪门控",避免在服务未就绪时执行测试导致误报;反射是"动态发现"能力,降低测试对 proto 文件的硬依赖。二者分别解决"何时测"与"测什么接口"的问题,是 gRPC 测试框架的基石。生产环境是否开启反射需权衡(可能泄露接口信息),测试环境通常开启。

#
★★

11. REST API 幂等性测试如何设计,为何 GET/PUT/DELETE 幂等而 POST 不幂等,如何用 Idempotency-Key 头(Stripe 模式)验证重复提交、超时重试与并发请求只生效一次,服务端对同 key 应返回缓存结果而非重复执行?

REST API 幂等性测试如何设计?为何 GET/PUT/DELETE 幂等而 POST 不幂等,如何用 Idempotency-Key 头验证重复提交、超时重试与并发请求只生效一次?

  • HTTP 方法幂等语义(GET/PUT/DELETE 幂等,POST 不幂等)
  • Idempotency-Key 头(Stripe 模式)的实现机制
  • 重复提交、超时重试、并发请求的用例设计

HTTP 方法幂等语义:GET 是安全且幂等(不改变状态),PUT 与 DELETE 幂等(重复执行结果一致),而 POST 语义上不幂等(每次创建新资源)。幂等性测试因此要验证:GET 重复调用返回相同结果且无副作用;PUT 重复提交同一请求,最终状态一致且不产生重复副作用;DELETE 重复删除返回相同的处理结果(如 204 或 404);POST 默认不幂等,需应用层保证。Idempotency-Key 模式(Stripe):客户端为写操作生成唯一 key,服务端对同一 key 缓存首次请求的结果,后续相同 key 的请求直接返回缓存结果而不重复执行。测试用例包括:重复提交同一 key 返回与首次相同的结果(响应体、状态码一致);超时重试(首次超时后客户端重试,服务端返回缓存结果而非重复扣款/创建);并发请求(多个相同 key 并发到达,保证只执行一次,其余返回同一结果);不同 key 的请求则正常独立执行。服务端实现需用数据库唯一约束或原子操作保证 key 单次生效。

幂等性测试的关键是"重复执行无副作用"与"同 key 返回缓存结果"。GET/PUT/DELETE 的幂等来自 HTTP 语义,POST 的幂等依赖应用层 Idempotency-Key。并发与超时重试是最易出现重复执行的场景,必须用并发与重试用例验证"只生效一次"。缓存结果与首次执行结果的一致性断言是验证核心。

// 验证同 key 重复提交只生效一次
String key = "idem-" + UUID.randomUUID();
Response first = given().header("Idempotency-Key", key)
    .body("{\"amount\":100}").post("/payments");
Response retry = given().header("Idempotency-Key", key)
    .body("{\"amount\":100}").post("/payments");
assertThat(retry.statusCode()).isEqualTo(first.statusCode());
assertThat(retry.body().asString()).isEqualTo(first.body().asString());
#
★★

12. Webhook 异步回调的测试要点,如何验证签名(HMAC-SHA256 与时间戳容差)、失败重试与指数退避、乱序/重复投递的幂等去重,并用 webhook.site/ngrok 隧道本地接收真实回调做端到端验证?

Webhook 异步回调的测试要点有哪些?如何验证签名、失败重试与指数退避、乱序/重复投递的幂等去重?

  • 签名验证(HMAC-SHA256 与时间戳容差)
  • 失败重试与指数退避
  • 乱序/重复投递的幂等去重

Webhook 测试要点如下。签名验证:Webhook 通常用 HMAC-SHA256 对 payload 签名,测试需验证正确签名通过、错误签名/篡改 payload 被拒绝、时间戳容差(timestamp tolerance)防止重放攻击,即过期时间戳被拒,字段完整性(如 header 中的 timestamp + signature)校验存在。失败重试与指数退避:测试服务端在接收方返回非 2xx 时重试,重试间隔按指数退避递增(如 2^n 秒),并设最大重试次数;验证重试次数上限、间隔单调递增、以及接收方恢复后重试成功。幂等去重:Webhook 可能乱序或重复投递,测试以 event id 去重,验证重复投递被忽略、乱序投递按状态或 id 处理(如 idempotent consumption),确保处理结果一致。端到端验证:用 webhook.site 或 ngrok 隧道把本地接收端暴露到公网,接收真实回调,验证真实网络下的签名、时序与重试链路,而不仅用 mock。综合测试覆盖签名、重试、去重与真实网络链路四层。

Webhook 是异步外部回调,安全与可靠性依赖签名、重试、幂等设计。签名与时间戳防重放是安全校验,指数退避与幂等去重是可靠性保障,webhook.site/ngrok 提供真实链路验证。四者共同构成 Webhook 测试的完整闭环。

#
★★

13. OpenAPI/Swagger 文档驱动的接口测试,如何从规范自动生成用例并验证实现与文档的一致性?

OpenAPI/Swagger 文档驱动的接口测试如何实现?如何从规范自动生成用例并验证实现与文档的一致性?

  • OpenAPI/Swagger 规范作为契约来源
  • 从规范自动生成测试用例
  • 实现与文档一致性的验证(schema 校验、契约测试)

文档驱动测试以 OpenAPI/Swagger 规范(openapi.yaml/json)作为单一契约来源。从规范自动生成用例:解析规范中的 paths、operations、parameters、requestBody 与 responses,自动生成针对每个端点、参数、状态码与响应 schema 的测试用例;工具如 Dredd、Schemathesis、Swagger Codegen 测试模板、Postman 的 OpenAPI 导入等,可基于规范批量生成请求并断言响应符合 schema。验证实现与文档一致性:对每个响应做 schema 校验(响应 JSON 符合 OpenAPI 中定义的 schema),验证参数、必填、枚举、格式与默认值;同时验证文档中的端点/方法/状态码在实现中真实存在且行为一致,防止"文档与实现漂移"。Schemathesis 等工具还能基于规范做属性驱动测试(fuzz schema 边界),自动发现未覆盖的边界与错误。文档驱动测试的价值在于"规范即契约",实现与文档保持一致,避免手工维护测试用例。

文档驱动测试把规范当作可执行契约,实现"规范→用例→校验"的自动化链路。核心是验证实现符合规范(schema 校验 + 行为一致性),防止文档漂移。借助自动化工具能显著降低用例维护成本,是契约测试在 REST 领域的一种轻量实现。

#
★★

14. 接口测试中的编码与字符集问题,Content-Type、URL 编码、JSON 转义与 Unicode 边界如何覆盖?

接口测试中的编码与字符集问题如何覆盖?Content-Type、URL 编码、JSON 转义与 Unicode 边界如何测试?

  • Content-Type 与字符集(charset)的设置与校验
  • URL 编码与特殊字符处理
  • JSON 转义与 Unicode 边界(emoji、中文、代理对)

编码与字符集测试需覆盖四层。Content-Type 与字符集:验证请求 Content-Type 正确(如 application/json; charset=utf-8),服务端正确解析并回显正确字符集;测试缺失或错误的 charset 时服务端的处理(错误 415 或按默认解析);验证响应头 Content-Type 与 body 实际编码一致。URL 编码:测试特殊字符(空格、&、=、?、#、非 ASCII 字符)在 query 与 path 中的正确 URL 编码与解码,验证参数值经编码后不被截断或误解析;测试 URL 编码的边界(%2F、%00 等)。JSON 转义:测试 JSON 中的引号、反斜杠、换行、控制字符的转义,验证请求体与响应体的转义往返一致。Unicode 边界:测试中文、emoji、代理对(surrogate pair)、组合字符、零宽字符等,验证存储与回显后的 Unicode 一致性(不出现乱码、替换字符或截断)。综合测试需覆盖 GBK/UTF-8/Latin-1 等字符集交叉、大小写与规范化(NFC/NFD)处理。

编码问题在跨语言、跨系统时极易产生乱码与数据损坏,属于隐蔽缺陷。测试应覆盖声明、传输、解析、存储、回显全链路,并针对 Unicode 边界与特殊字符做专项用例。字符集一致性(请求头、响应头、body 实际字节)是验证核心。

#

15. API 版本兼容性测试,如何验证新旧版本客户端与服务端的兼容性?

API 版本兼容性测试如何设计?如何验证新旧版本客户端与服务端的兼容性?

  • 版本策略(URL 路径、Header、查询参数)
  • 向后兼容与向前兼容的验证
  • 新旧客户端与服务端的组合矩阵

版本兼容性测试围绕"向后兼容"(旧客户端调用新服务端)与"向前兼容"(新客户端调用旧服务端)设计。版本策略:明确版本号放在 URL 路径(/v1/)、Header(Accept-Version)或查询参数,并统一验证。向后兼容:新版本服务端不得破坏旧客户端依赖的字段、语义与响应结构,需验证旧客户端仍能正常工作(响应兼容、无破坏性变更、字段缺失时的默认值)。向前兼容:新客户端对旧服务端应能降级处理(如新字段缺失时不崩溃)。组合矩阵:构建"客户端版本 × 服务端版本"的正交矩阵,尤其关注 N-1、N 与 N+1 组合,验证每个组合的请求/响应契约。同时验证:新增字段是可选且不破坏旧端解析;废弃字段有弃用期与迁移窗口;扩展字段(如 JSON 中新增字段)对旧客户端透明。测试常用契约测试(Pact)与 schema 兼容性校验(如 JSON Schema 的 additionalProperties)来防止破坏性变更。

版本兼容的本质是"契约的渐进演进"。组合矩阵能暴露单一版本测试无法发现的兼容性问题,向后兼容是生产安全底线,向前兼容是灰度发布前提。对响应结构做宽松解析(忽略未知字段)与对请求做宽松扩展(容忍额外字段)是兼容性的实现基础。

#

16. 契约测试中 Provider 侧如何用"待验证契约列表"管理多消费方版本兼容?

契约测试中 Provider 侧如何用"待验证契约列表"管理多消费方版本兼容?

  • 待验证契约列表(pending/verification contract list)的概念
  • 多消费方版本的管理
  • 版本兼容与发布决策

Provider 侧通过"待验证契约列表"(即 Pact 中 provider 版本的待验证契约集合,含各 consumer 的 contract 与其版本)管理多消费方兼容。其机制是:Provider 在发布新版本前,从 Pact Broker 拉取所有已发布消费者的契约(按 consumer 版本与 tag 过滤),形成"待验证列表",逐一运行 provider verification,确保新 Provider 版本对每个消费者契约都通过。若某消费者的契约未通过,则该消费者因此被破坏,Provider 不得发布。多消费方版本兼容的要点:列表应包含每个消费者的最新版本契约,而非仅默认分支;配合 consumer 的 tag(如 prod、staging)区分环境;对仍处活跃期的旧版本契约也纳入验证,防止破坏存量消费者;通过 can-i-deploy 判定某 Provider 版本能否安全发布到某环境。这样"待验证契约列表"成为 Provider 发布的安全门禁,确保新增/变更不破坏任何已部署消费者。

单一契约测试无法覆盖多消费方,因此需要"待验证列表"聚合所有消费者契约。它把"Provider 变更是否破坏消费者"从人工判断变成自动化门禁,是 CDC 在微服务中能落地的关键机制。版本与 tag 过滤保证列表只包含真实、活跃的消费者契约。

#

17. GraphQL 测试,查询、变量与 Schema?

GraphQL 测试中查询、变量与 Schema 的作用与测试要点是什么?

  • 查询(query)与变量(variables)的分离
  • 变量类型与默认值校验
  • Schema 作为类型契约的验证

GraphQL 测试围绕查询、变量与 Schema 三要素。查询(query):定义要获取的字段与嵌套结构,是测试的"请求体",测试需验证查询的正确性、字段选择、别名与指令(@include/@skip)的效果。变量(variables):查询常与变量分离,测试需验证变量类型(声明类型与实际传入类型匹配)、必填变量缺失时的错误、变量默认值、以及变量传值对结果的影响;变量让同一查询可复用,测试用不同变量组合覆盖边界。Schema:定义类型、字段、参数与枚举,是"类型契约";测试用 introspection 验证 schema 与类型定义一致,验证类型校验(错误类型/字段在执行前被拒绝)、枚举值、非空约束与接口/联合类型。综合测试要点:查询的正确性与字段选择、变量的类型与默认值、Schema 的类型契约与校验,三者共同保证 GraphQL 请求的可靠性与类型安全。

查询、变量、Schema 三者构成 GraphQL 请求的完整模型。变量分离带来可复用性,Schema 提供类型安全与契约校验。测试需同时覆盖"查询正确性、变量类型边界、Schema 一致性",才能系统验证 GraphQL 接口。

#

18. REST API 的错误码体系测试,业务错误码、HTTP 状态码与错误响应体的对应关系如何验证?

REST API 的错误码体系测试如何验证业务错误码、HTTP 状态码与错误响应体的对应关系?

  • 业务错误码与 HTTP 状态码的映射
  • 错误响应体的结构统一性
  • 错误码的枚举与文档一致性

错误码体系测试验证"业务错误码、HTTP 状态码、错误响应体"三者的对应关系。映射关系:每个业务错误码应映射到合适的 HTTP 状态码(如参数错误→400、未认证→401、无权限→403、资源不存在→404、资源冲突→409),测试验证这种映射正确且一致,不出现业务码与状态码矛盾(如业务码表示"未找到"但状态码是 200)。错误响应体结构:验证错误响应体格式统一(含 error code、message、details、trace id、request id 等字段),字段名、类型与必填性一致,不同错误返回相同结构便于客户端解析。枚举与文档一致性:验证业务错误码是受控枚举,错误码在文档(OpenAPI)中有定义,实际返回的错误码与文档一致,无未定义的错误码。测试还需覆盖:错误码的唯一性(不重复、语义清晰)、错误信息可读性(不泄露内部细节)、以及错误码的兼容性(新增错误码不破坏旧客户端解析)。综合验证为保证错误体系的统一、可诊断与可演进。

错误体系是 API 可诊断性的重要部分。测试的关键是验证"业务码—状态码—错误体"三者的一致映射,防止语义矛盾。统一错误结构让客户端有一套解析逻辑,错误码枚举与文档一致保证可维护性。三者一致性是错误体系测试的核心。

// 验证业务错误码与状态码、错误体的对应关系
given().get("/users/{id}", "not-exist")
    .then()
    .statusCode(404)
    .body("code", equalTo("RESOURCE_NOT_FOUND"))
    .body("message", not(emptyOrNullString()))
    .body("traceId", not(emptyOrNullString()));
#

19. API 的分页、排序与过滤参数测试,cursor/offset 分页、排序稳定性与过滤组合如何设计用例?

API 的分页、排序与过滤参数测试如何设计?cursor/offset 分页、排序稳定性与过滤组合如何设计用例?

  • cursor 与 offset 分页的边界用例
  • 排序稳定性与多字段排序
  • 过滤条件的组合与边界

分页测试:offset 分页验证页码与页大小(page size)、越界页(超出数据总量)、并发生成数据时 offset 分页的重复/漏掉问题;cursor 分页验证 cursor 的生成与解析、游标失效(数据被删除)、游标指向的边界、以及翻页时数据不变性(基于 cursor 的位置而非偏移)。排序测试:验证单字段排序、多字段排序(主序+次序)、排序字段的合法性(非法字段报错)、排序稳定性(相同排序键的记录顺序确定,通常需补充稳定排序键如 id)、升序/降序、以及排序与分页结合时的正确性。过滤测试:验证单条件过滤、多条件组合(AND/OR 语义)、过滤字段的边界(空值、未提供的字段、非法值)、模糊匹配与精确匹配、以及过滤与分页/排序的组合(过滤后分页总数正确)。综合用例需覆盖空数据集、全量返回、极端页大小、组合参数交叉等边界,保证分页、排序、过滤三者协同正确。

分页、排序、过滤是列表 API 的通用能力,三者组合后边界情况复杂。cursor 分页与 offset 分页在并发生成数据下的行为不同,需分别验证。排序稳定性需补充稳定键,过滤组合需验证逻辑语义。组合测试是列表 API 质量的关键。

#

20. API 测试中的时间与并发边界,时间戳校验、限流触发与并发写冲突如何构造验证?

API 测试中的时间与并发边界如何构造验证?时间戳校验、限流触发与并发写冲突如何设计用例?

  • 时间戳校验与时间边界
  • 限流(rate limit)触发与恢复
  • 并发写冲突(乐观锁、幂等)的验证

时间与并发边界测试需构造特定场景。时间戳校验:验证请求中的时间戳(如 created_at、expires_at、签名时间戳)的边界,包括过期时间戳被拒、未来时间戳、时区(UTC 与本地时间)与夏令时边界、闰秒/毫秒精度;可通过注入时间源或控制时钟验证边界。限流触发:按策略构造请求速率,验证超过阈值后返回 429(Rate Limit Exceeded)与 Retry-After 头,验证限流窗口(固定窗口/滑动窗口)的边界、窗口重置后恢复、以及不同用户的限流隔离。并发写冲突:用并发请求验证乐观锁(乐观锁版本号 version 冲突时返回 409 或冲突错误)、条件更新(If-Match/ETag 校验)、以及并发写同一资源时只生效一次(配合幂等);验证并发下的数据一致性(无丢失更新、无脏写)。综合用例需用真实并发(多线程/多客户端)与可控时钟(模拟时间)构造,确保边界可复现。

时间与并发是接口测试中最难稳定复现的边界。时间戳校验依赖可控时钟,限流依赖速率控制,并发写冲突依赖真实并发。三者都需构造性测试(注入时钟、制造并发、触发限流)而非依赖偶然,才能可靠验证边界行为。