接受集成之前,先读懂 mock 演示
本文目录
本地预览可以展示预期交互,而它的服务响应仍然来自示例数据。这样的原型可能很有用。接受更大的任务之前,先确认哪些部分实际运行过,哪些结果是示例数据提供的。
提出一个具体问题:当视图显示“Saved”时,是应用展示了预先提供的成功值,还是调用了预期的适配器、收到了真实服务结果,或是在后续读取中验证了该值?这些是不同的证据。
Python 的 mock 文档 介绍了如何替换被测系统的某些部分,并断言这些替代对象如何被使用。这是一种有用的测试技术。针对替代对象的检查,只能确立关于那条测试路径的主张;它并没有观察被替代的服务。
区分完整请求与原型里程碑
考虑下面这个笔记应用的虚构请求:
任务 NOTE-5:让有权限的用户把 N17 的标签从 Draft 改为 Ready。
完整流程:
只有实际服务确认变更之后,才显示 Saved。
用户重新打开记录时,读取它当前已保存的标签。
如果保存失败,解释未保存的状态,并保留用户拟定的标签,
供其修正。使用应用现有的访问检查;
不要自行发明新的权限模型。
仅限首次交付:
准备可检查的本地原型源文件,使用示例响应,
明确标注未连接服务,附上边界图,并检查
假响应状态模型。记录尚未进行的浏览器检查。
本里程碑不连接服务、不使用真实记录,也不部署。
这份请求允许交付原型,但没有把原型定义为完整集成。分别审查这两类交付,既能避免拒绝有用的原型工作,也能避免接受尚未运行过的服务路径。
这个案例中的一切都是编写的教学材料:记录 N17、请求、示例数据、组件和审查回复。没有涉及真实记录或提供方。
追踪预先提供的成功值
初始示例数据是:
{"record_id":"N17","label":"Draft"}
收到保存请求时,fake 适配器返回这份单独的合成响应:
{"record_id":"N17","label":"Ready","saved":true}
它不联系服务。在这个纯 Python 教学对应模型中,完整的适配器和本地模型如下:
class FakeLabelAdapter:
def __init__(self):
self.calls = []
def save_label(self, record_id, label):
self.calls.append((record_id, label))
return {"record_id": record_id, "label": label, "saved": True}
class DemoPanel:
def __init__(self, adapter):
self.adapter = adapter
self.label = "Draft"
self.notice = "Not saved"
def save(self):
response = self.adapter.save_label("N17", "Ready")
self.label = response["label"]
self.notice = "Saved" if response["saved"] else "Not saved"
saved 字段为 true,是因为 fake 返回了 true。模型的提示状态由这个字段决定。这个小示例的其他地方,没有隐藏着一次存储写入。
配套的独立 HTML 原型 提供了对应的本地交互,并醒目标注 LOCAL MOCK DEMO · NO NETWORK OR STORAGE。它没有服务调用,选择 Reopen fixture 时,会把显示标签重置为初始值。作为本文的一部分,它的浏览器行为没有被运行过。对 Python 对应模型的方法检查,与浏览器点击或页面渲染检查是分开的。
评价演示之前,先画出边界
| 阶段 | 这个产物包含什么 | 这里可用的证据 |
|---|---|---|
| 初始本地状态 | N17 初始值为 Draft | 完整源文件和编写的示例数据 |
| fake 保存调用 | 记录 N17/Ready 这组参数,并返回成功值 | 实际的本地 Python 模型检查 |
| 本地状态变化 | 模型变为 Ready,提示为 Saved | 实际的本地 Python 模型检查 |
| HTML 事件与渲染 | 源文件根据假响应设置标签和提示 | 已提供源文件;未运行浏览器 |
| 实际适配器与服务 | 没有连接任何调用路径 | 未运行 |
| 持久值与后续读取 | 没有使用存储 | 未运行 |
| 当前用户的访问权限 | 示例中不存在真实身份或访问路径 | 未运行 |
如果有人实际运行本地预览,并看到 Ready,这项观察可以支持“使用给定示例数据进行了渲染”的结论。但它仍然不能证明服务保存成功。对于这里提供的文件,连这项渲染观察也尚未进行;上面的图片是边界示意图,不是浏览器截图。
检查小型模型实际做了什么
本地教学运行使用 Python 3.9.6,检查了两件事:
- 调用
save()会在 fake 中精确记录("N17", "Ready"),并把该模型状态改为Ready/Saved。 - 使用同一个适配器创建新模型,会再次从
Draft/Not saved开始。适配器中仍只记录了一次调用;它没有提供已保存记录的读取。
两项模型检查都通过了。它们没有运行 HTML、JavaScript、浏览器、服务、身份验证或存储。实际输出保留在本地模型日志中。
下面是状态历史,观察范围保持明确:
| 步骤 | 模型动作 | 之后的标签 / 提示 | 能得出什么 |
|---|---|---|---|
| 1 | 构造第一个模型 | Draft / Not saved | 初始示例状态 |
| 2 | 调用它的 save 方法 | Ready / Saved | 此模型使用了假响应 |
| 3 | 检查 fake 调用 | 仍为 Ready / Saved;记录了一次 N17/Ready 调用 | 预期参数到达了 fake |
| 4 | 构造新模型 | Draft / Not saved;同一个 fake 仍只有一次调用 | 示例没有持久化读取路径 |
第 4 步是这个教学原型本身的属性,不是实际观察到的真实服务故障。模型被设计为从 Draft 初始化,并且没有持久化。把它报告成“后端把保存丢了”会造成误导,因为这里没有联系任何后端。
fake 仍然有用。它让开发者无须配置服务,就能检查响应分支和预期调用。其他示例响应也可以用来运行失败分支,但这里提供的原型没有实现 NOTE-5 完整的失败处理。这是一项已经识别的后续工作,不是已完成的检查。
为每项验收主张匹配适当证据
| 关于 NOTE-5 的主张 | 原型能够支持什么 | 更大范围的主张还需要什么 |
|---|---|---|
| 请求把 N17 和 Ready 发送给选定的依赖 | Python 对应模型把这些参数发送给了自己的 fake | 验证实际应用的适配器路径和参数 |
| 给定的成功响应更新本地状态 | 已在 Python 模型中检查 | 检查实际组件、事件和渲染路径 |
| 视图显示预期标签 | 已提供可检查的 HTML | 声称检查过之前,先在浏览器中观察渲染后的原型 |
| 服务保存了变更 | 这里没有任何证据观察到服务 | 获授权的真实保存路径的证据 |
| 重新打开时显示已保存的值 | 新模型构造会返回示例初始值 Draft | 根据已接受的服务写入,检查实际的后续读取 |
| 保存失败时保留拟定标签并解释错误 | 这个仅有成功响应的示例没有实现 | 按适用契约实现并检查这条路径 |
| 只有有权限的用户才能修改记录 | 不存在真实用户或访问路径 | 检查并验证实际的访问控制 |
| 流程已经部署 | 这里没有发布产物或部署 | 单独的发布及其验证 |
集成决定不必要求所有可能的测试。它需要与承诺边界相关的证据。对于这份请求,关键缺口是从实际适配器经过服务、再到后续读取的这段路径,以及相关的失败和访问行为。重复仅针对示例数据的检查,并不能跨过这段边界。
写出两种不同的验收回复
第一份回复接受实际请求的里程碑:
接受 NOTE-5 的原型源文件和 fake 状态模型里程碑。
给定 HTML 已明确标注为未连接服务的 mock 演示。
边界图标出了 fake 和未运行的服务路径。
记录的 Python 检查支持 fake 调用参数和本地状态变化,
包括新模型重置为 Draft。
这个决定覆盖这些源文件和模型产物。未检查浏览器交互,
实际保存、读取、访问和失败路径也尚未实现或接受。
保持完整 NOTE-5 流程未完成。
第二份回复针对“完整集成已经完成”这一拟议主张:
不要凭 mock 演示关闭端到端 NOTE-5 任务。
其中的 saved=true 来自假响应,不是服务结果。
下一步,在选定代码库中识别实际适配器、保存操作和后续
读取路径。返回有明确范围的集成方案,列出精确候选与文件、
适用的访问检查、失败行为,以及最小的相关验证步骤。
保留原型证据的原型标识。不要用编造的服务输出替换它,
也不要重复本地 fake 检查来证明持久化。
任何后续真实环境检查,都必须使用获授权的范围和数据。
这份规划回复不要求调用服务、设置账号、修改线上记录
或发布。
两份回复都没有把 mock 当成缺陷。一份接受有用且有限的产物;另一份保留原始请求中尚未满足的部分。
复用这份演示审查请求
按[原始需求和当前正在验收的里程碑]
审查[精确演示候选]。只读工作。
在适用时,追踪演示动作,从输入经过本地状态、适配器、
依赖、保存结果,再到后续读取。为每个阶段标注:
实际运行过、模拟、仅检查了源文件,或尚未确立。
标明精确的示例数据,以及预先提供的成功或失败值。
对每项主张,说明演示路径能支持什么,以及它没有跨过
哪条边界。fake 调用断言可以支持调用契约;
不能把它报告为观察了被替代的服务。
编写绘制的图片或尚未运行的 HTML,不能变成浏览器测试结果。
返回当前里程碑的限定范围决定,以及针对更大范围未满足
需求的最小后续方案或检查。保留有用的 mock 检查。
本次审查不调用账号、不修改线上数据、不安装服务,也不部署。
将实际执行与示例分开记录。
这样可以更好地使用演示:接受它已经确立的部分,保留示例数据用于后续开发,并要求提供跨越下一条边界所需的具体证据。