读者视角导读
Mock 不会告诉你供应商改了什么
WP23 导读:真实数据测试不是为了消灭 mock,而是让供应商差异在到达 UAT 或生产之前暴露。
最贵的 bug 不是没测到的那种,而是所有测试都通过、到了生产环境才失败的那种。在酒店分销领域,这不是理论风险,而是默认结果——你的测试套件模拟的是理想供应商行为,真实供应商返回的却是部分响应、限流错误和与自身文档都不一致的 payload 结构。
多数团队意识到了这个问题。他们的应对方式是加更多 mock、更多合成数据、更多本地测试固件。结果是测试套件体积膨胀,预测能力却在萎缩。HotelByte 的应对方式截然不同:一个独立的 E2E 应用,用真实凭证调用线上 API,创建真实预订,再取消它们。目标不是消灭 mock,而是确保 mock 不是最后一道防线。
Mock 掩盖的三类失败
结构漂移。 供应商改了字段名、加了嵌套对象、把关键值挪进了注释字段。集成时冻结的 mock 继续通过,生产环境却遭遇反序列化错误或静默数据丢失。
状态盲区。 一个 mock 了供应商响应的预订测试,无法验证预订是否真实存在于供应商系统中,取消政策是否正确传递,确认号是否对应真实记录。
延迟幻觉。 Mock 在毫秒级返回。真实供应商 API 的响应时间因大洲、时段和限流窗口而异。基于 mock 配置的超时在生产环境要么误杀健康请求,要么在降级场景下等待过久。
HotelByte 的 E2E 框架(api/tests/)就是为了在这些问题到达 UAT 之前暴露它们而设计的。它使用与外部集成方相同的 sdk/go 客户端,用真实凭证认证,覆盖搜索、验价、可订性检查、预订、取消和订单查询等 40+ 场景。预订测试创建真实预订,取消测试将其作废。没有 stub、没有进程内短路、没有合成库存。
边界规则:层内真实,跨层 mock
HotelByte 并非拒绝所有 mock。规则很精确:同一架构层内的调用使用真实实现,跨层边界的调用才允许 mock。领域测试调用真实领域方法,服务测试 mock 它依赖的 DAO,但执行真实的服务逻辑。这防止了测试套件在验证 mock 框架而非生产代码,同时保证单元测试足够快,可以在每次提交时运行。
代价是测试执行时间和成本。真实数据 E2E 比 mock 套件慢,真实预订会消耗供应商配额。HotelByte 用 500 断言阈值管理这个问题——低于阈值的运行会被标记为验证面不完整;增量报告对比则能在所有场景通过时仍发现静默的测试收缩。覆盖率底线在 CI 中强制执行:领域逻辑 100%,数据访问层 80%+,服务层 70%+。低于层级阈值的 PR 会被阻断。
这要求什么
零容忍的硬编码测试数据政策意味着工程师不能扔一个 JSON fixture 进测试文件就完事。每个测试输入必须来自真实来源或显式管理的测试账户。这比合成数据慢,而且需要一个跨所有场景维护的统一测试账户矩阵(平台管理员、租户用户、OpenAPI 客户)。
回报是:当测试失败时,失败是有信息量的。它反映的是真实供应商行为变更、真实数据形状异常或真实回归——而不是一个从未更新的 mock。
阅读路径
从“核心设计原则”中的”证据先于叙事”开始。这是理解为什么真实数据测试是架构约束而非测试偏好的最清晰表述。
想了解运行机制的读者,重点看“架构机制”中的 40+ E2E 场景、真实数据优先原则、断言数量阈值、分层覆盖率目标,以及供应商样本和回放数据的持续积累。
关注治理视角的读者可以阅读“验证路径”:外部评审如何运行核心 E2E 场景、检查测试是否使用真实供应商样本或录制数据、统计断言覆盖的关键字段、验证脱敏样本不泄露凭证和 PII。
评论