E02第 1 / 1 课时未开始内容版本 1.0.0 · 核验于 2026-10-26

测试层次与业务风险

测试层次与业务风险 · 阅读后完成下方实验与检查题,再用「标记完成」记录进度。

学习目标

读完本课你能:把单元、接口、浏览器三层测试各自「验证什么 / 不能证明什么」说清楚;按业务风险给学习平台的功能分配测试层;看懂本站三层测试的真实分布并补上薄弱处。

问题场景

你给课程判分逻辑改了一行,手测两个题都对,就提交了。三天后你发现:多选题全选时判分永远错误。手测是抽查,且最容易抽到的路径恰恰是你刚改过的——测试要解决的就是这个盲区:用固定的、可重复的检查覆盖你抽查不到的组合。但测试不是越多越好,也不是都堆在同一层。

核心解释

三层各管一段,谁也不能替代谁:

层 本站的实现 验证什么 不能证明什么
单元 vitest run,测纯函数 判分规则、SSE 解析、检索打分等逻辑正确 路由真的挂上了、UI 真的渲染了
接口 对 Route Handler 发请求 参数校验、状态码、错误分类 浏览器里用户看到什么
浏览器 Playwright 无头 Chromium(scripts/e2e-core.mjs,19 项) 真实用户流程:搜索→阅读→答题→笔记 所有数据组合;跑得慢(分钟级)、依赖环境、会脆

按业务风险分配,不是均匀撒: 判分错误会直接教错学习者 → 单元层必须穷举边界(多选、漏选、全选);SSE 分包解析错了中文就乱码 → 单元层用「半包数据」构造用例;课程正文渲染坏了影响所有阅读 → 浏览器层一条检查盯住「代码块渲染 + 语法高亮」;用量记账偶尔少一条不影响使用 → 可以容忍低覆盖。

本站 e2e 的 19 项就是按这条原则挑的——每项对应一条「坏了会很疼」的用户路径:

// scripts/e2e-core.mjs(节选):每条检查都对应业务风险
record("全局搜索命中 R08", await hit.isVisible().catch(() => false));
record("正文代码块渲染", codeBlocks >= 2, `${codeBlocks} 个`);
record("课程检查题判分", graded);
record("刷新后完成状态保留", /* … */);

「不能证明什么」同样重要:单元测试 100% 通过证明不了页面能打开;e2e 全绿证明不了 300 道题的判分都对——它只验证了样例里那几题。层级越高,覆盖越「宽而浅」;层级越低,覆盖越「窄而深」,两头都要有。

示例拆解

给判分逻辑写一个单元测试,体会「窄而深」:

// 多选题边界穷举:手测最爱漏的恰恰是这些
test("答案 {A,B},选 {A}(漏选)应判错", () => {
  expect(gradeMultiple(["A", "B"], ["A"])).toBe(false);
});
test("答案 {A,B},选 {B,A}(顺序颠倒)判对", () => {
  expect(gradeMultiple(["A", "B"], ["B", "A"])).toBe(true);
});

关键点:边界是风险所在——漏选、顺序颠倒、重复选择,这类测试毫秒级跑完,可以进每次检查链(E01)。同样的边界穷举放 e2e 里做?每条用例要点页面、等渲染,分钟级变小时级,还全卡在 UI 上——测哪层,先看这个风险属于逻辑还是交互。

本站三层现状:单元与接口测试在 npm run test(vitest),浏览器层在 node scripts/e2e-core.mjs(需先 build + start)。两层跑法不同、频率不同:前者进日常检查链,后者进交付前回归。

动手任务

  1. 列出本站 5 个功能(判分、搜索、笔记、沙箱、AI 聊天),各标注「该测哪层、为什么」,与现状对照找缺口。
  2. 给一个纯函数(如检索打分或判分)补 2 个边界测试,跑 npm run test 确认通过。
  3. 把 e2e 某一项的断言临时改严格让它 FAIL,体会浏览器层「抓的是用户路径坏了」这个定位,然后改回来。

常见错误

  • 全押 e2e:什么测试都往浏览器层塞,套件慢到没人肯跑,最后形同虚设。
  • 测实现不测行为:断言函数内部调用了某方法,重构一改名就全红——测试应该盯输入输出,不盯内部步骤。
  • 追求覆盖率数字:100% 覆盖但全是「调用不抛异常」的空测,覆盖了行数没覆盖风险。
  • 忘了测「不能做什么」:参数校验的 400、未配置时的降级,失败路径比成功路径更容易坏。

检查与复盘

  • 三层各自的「验证什么 / 不能证明什么」各能说出一条
  • 新功能出现时,能按风险先选层再写测试
  • 检查链里单测全绿、交付前 e2e 全绿,两层分开对待

参考资料

检查题共 3 题,提交后立即显示解析
答案由服务端判定;答错的题会自动进入复习计划。
Q1单选简单

单元测试、接口测试、E2E 测试各自主要证明什么?

Q2读代码简单

阅读这个 vitest 用例(摘自数据层测试)。它证明了什么、没证明什么?

// tests/db.test.ts
import { expect, test } from 'vitest';
import { createNote } from '@/lib/db/notes';

test('重复标题插入被唯一约束拒绝', () => {
  createNote('学习笔记');
  expect(() => createNote('学习笔记')).toThrow(/UNIQUE/);
});
Q3多选中等(多选,全部选对才算正确)

下列断言,哪些适合放进单元测试而不是 E2E?(多选)

读完这一课了?

标记完成后,工作台会安排接下来的学习。

Command Palette

Search for a command to run...