Skip to content
签到签到

第 13 章:测试、质量体系与评估

本章定位

资深前端要能设计测试体系,而不是只写“能跑的测试”。AI Agent 输出不确定,所以还需要 fixture、回放、快照和评估集。

必须掌握清单

必须掌握

  • 能区分单元测试、集成测试和 E2E 测试。

    相关答案: 单元测试隔离验证小范围逻辑,集成测试验证多个真实模块之间的契约,E2E 从用户入口验证完整关键路径。测试层级应按风险组合,不能把所有行为都塞进慢且难定位的 E2E。

    具体例子: 状态 reducer 用单元测试,SSE 解析器与消息 store 用集成测试,用户登录后发送消息并停止生成用 E2E 测试。

  • 能让测试不依赖真实模型和 API Key。

    相关答案: 在 LLM Provider 边界注入可控 fake,按测试脚本返回固定 token、工具调用、错误或延迟。这样测试无需网络和密钥,结果可重复;少量真实模型验证应作为单独的评估任务运行。

    具体例子: FakeProvider 依次产生文本 token、工具调用和结束事件,测试断言 UI 状态转换;CI 不读取生产 API Key,也不会因模型输出变化随机失败。

  • 能用 fixture 回放会话和工具结果。

    相关答案: fixture 保存经过脱敏、带版本的输入事件和预期关键结果,回放器按原顺序或受控时钟重放。fixture 应覆盖成功、失败、取消和旧版本兼容,不能直接复制含隐私的生产日志。

    具体例子: 保存一段“助手请求搜索—工具超时—用户重试—成功”的事件序列,测试时回放并断言最终消息、错误提示和重试按钮状态。

  • 能设计确定性的快照测试。

    相关答案: 快照输入必须固定时间、随机数、ID、排序和环境差异,只保留稳定且有审查价值的结构。巨大 DOM 或包含动态字段的快照容易被无脑更新,不能替代针对关键行为的断言。

    具体例子: 用固定 clock 和 ID generator 生成消息视图,快照只记录消息类型与状态;token 文本、按钮禁用和错误码再用显式断言验证。

  • 能解释为什么覆盖率不是唯一目标。

    相关答案: 覆盖率只说明代码被执行过,不证明断言有效、边界正确或用户路径可靠。测试价值取决于风险覆盖、失败检测能力和可维护性,还应关注变异测试、缺陷回归和关键路径成功率。

    具体例子: 一个测试调用权限函数却不检查返回值也能覆盖 100% 行;补上 allow、deny、ask 和非法参数断言后,覆盖率可能不变,但真正能阻止安全回归。

原理讲解

单元测试验证局部纯逻辑,集成测试验证多个模块协作,E2E 验证真实入口。AI 前端中,工具状态机、消息投影和权限决策适合单元测试,流式 UI 需要 fixture 和快照。

真实模型不可控,所以测试要把 LLM Provider 替换成固定输出。fixture 回放保存会话事件,测试时重放事件并断言 UI 和派生状态。

评估集是一组带预期结果的场景。它和普通测试不同,除了“对不对”,还要观察是否稳定、是否可解释、是否容易回归。

代码示例或模板

ts
function renderToolStatus(
  status: "pending" | "success" | "failed" | "cancelled",
): string {
  switch (status) {
    case "pending":
      return "执行中";
    case "success":
      return "成功";
    case "failed":
      return "失败";
    case "cancelled":
      return "已取消";
  }
}

const cases = [
  ["pending", "执行中"],
  ["success", "成功"],
  ["failed", "失败"],
  ["cancelled", "已取消"],
] as const;

for (const [status, expected] of cases) {
  console.assert(renderToolStatus(status) === expected);
}

这个例子没有依赖任何框架和模型,适合说明确定性测试。

AI Agent 概念对照

  • eval set 对应测试集。
  • keyless snapshot 对应确定性格言。
  • session replay 对应 fixture 回放。
  • tool tests 对应工具执行测试。

面试追问

1. AI 应用前端如何做不依赖真实模型的确定性测试?

查看深度解析

标准回答: 在 LLM Provider 边界注入 fake,用固定脚本产生 token、工具调用、用量、错误和延迟;同时固定时钟、ID 和调度器。测试验证事件到状态和 UI 的转换,不依赖网络、API Key 或模型随机输出。

原理展开: 生产模型属于非确定外部系统,应通过端口替换;真实模型质量另用隔离评估集和统计指标验证,不混入普通 CI。

工程示例: fixture 依次发出 text_deltatool_calltool_resultdone,测试断言工具卡状态和最终消息;虚拟时钟控制超时重连。

常见误区: mock 到内部实现函数导致重构即碎,或录制一次真实 HTTP 响应却包含密钥和动态字段。

继续追问: 如何测试 token 到达时序?

回答方向: fake stream 接收受控 scheduler,测试主动推进时间;断言关键状态而非真实等待毫秒。

2. 快照测试什么时候有价值,什么时候是负担?

查看深度解析

标准回答: 当输出结构稳定、人工审查差异有意义且难以逐项断言时有价值,例如事件投影或小型组件状态。包含时间、随机 ID、巨大 DOM 或频繁合法变化时,快照会制造噪声和盲目更新。

原理展开: 快照只证明输出发生变化,不解释行为是否正确;应与关键语义断言配合,并控制大小与确定性。

工程示例: 对工具状态机快照 {type,status,actions},同时显式断言失败时重试按钮可用;不快照整页 CSS 类和 SVG 路径。

常见误区: PR 中直接执行 update snapshots 而不阅读 diff,覆盖率看似增加却失去回归价值。

继续追问: 如何治理已有巨型快照?

回答方向: 按领域拆分、移除动态字段、把关键行为改为显式断言;无审查价值的快照直接删除并补更合适测试。

3. 工具调用链路更适合单元测试还是集成测试?

查看深度解析

标准回答: 两者都需要。参数校验、权限决策、状态 reducer 和错误映射适合单元测试;registry、权限层、执行器、事件日志和 UI 投影的契约必须用集成测试覆盖。少量 E2E 验证真实入口。

原理展开: 工具故障常发生在模块接缝,仅测各函数无法发现 call ID 丢失、错误形状不一致或清理顺序问题。

工程示例: 单元测试 allow/deny/ask 矩阵;集成测试回放“请求—确认—执行—取消”,断言只有一个最终事件且资源释放。

常见误区: 全部 mock 后所谓集成测试只验证 mock,或所有组合都走昂贵 E2E 导致慢且难定位。

继续追问: 高风险文件工具怎么测试?

回答方向: 使用临时沙箱目录和 fake process adapter,覆盖路径穿越、符号链接、超时和幂等;绝不操作真实用户文件。

4. 如何评估一个“看起来更好”的流式 UI?

查看深度解析

标准回答: 把主观判断转成任务与指标:首可见 token、稳定输出频率、INP、滚动稳定、取消成功、错误理解和任务完成率。用一致输入做可用性测试或 A/B,并结合用户偏好与技术指标。

原理展开: 更快动画不等于更好,过碎 token 会闪烁,过度合批会迟钝;还要评估无障碍读屏和弱网恢复。

工程示例: 两种合批策略在相同 fixture 下测试,记录 TTFT、提交次数、INP 和用户完成查找答案的时间。

常见误区: 让团队看 Demo 投票,样本、网络和内容都不一致;或只优化平均延迟忽略失败与长尾。

继续追问: 如何避免 A/B 指标互相伤害?

回答方向: 预先定义主指标和护栏,如完成率为主、错误率与 INP 为护栏,设置足够观测周期并按设备分层。

实践任务

为一个工具状态机编写 fixture 回放测试,验证执行中、成功、失败和取消状态。

验收标准

  • 测试不依赖 API Key 和网络。
  • 能稳定重放固定会话。
  • 能解释哪些逻辑不需要 E2E。

关联材料