7.6 KiB
7.6 KiB
DiffLens 测试策略与方案
规范化 DiffLens 的测试体系:分层、选型、覆盖重点、运行与质量门禁。 配套文档:《应用开发与版本迭代规范》
1. 目标与原则
- 保障正确性:核心 diff 算法与报告生成必须被单元测试覆盖,防止回归
- 可回归:每次迭代(
0.y.z)在前都能稳定跑通测试 - 简单优先:不做为测而测,优先覆盖纯逻辑与高风险模块
- 门禁前置:
npm test纳入提交/推送前的强制检查
2. 测试分层
| 层级 | 覆盖对象 | 工具 |
|---|---|---|
| 单元测试(UT) | 纯逻辑:diff 引擎、报告生成器 | Vitest |
| 组件测试 | React 组件:应用空态、工具栏交互 | Vitest + Testing Library |
| 集成(演进中) | Electron IPC / 多进程协作 | 预留 Playwright 或 Electron 测试 |
现阶段以单元 + 组件为主,覆盖最核心、最易回归的部分。
3. 技术栈
| 用途 | 选型 |
|---|---|
| 框架 | Vitest(与 Vite 生态一致,快) |
| 环境 | jsdom |
| React 测试 | @testing-library/react |
| 断言扩展 | @testing-library/jest-dom |
| 未来 E2E | Playwright(预留,暂不引入) |
4. 目录结构
vitest.config.ts # Vitest 配置(jsdom + 测试范围 + 覆盖率 80% 硬门禁)
src/renderer/src/
├── test/
│ └── setup.ts # 全局 setup:jest-dom 匹配器 + 自动 cleanup
├── diff/
│ ├── diffEngine.test.ts # diff 引擎单元测试
│ ├── diffWorker.ts # diff 计算 Web Worker(内联打包,覆盖率排除,逻辑由 diffEngine 覆盖)
│ ├── createDiffWorker.test.ts # worker 工厂(环境回退/实例化)
│ ├── createDiffWorker.ts # worker 工厂:环境不支持时返回 null 由调用方回退
│ ├── report.test.ts # 报告生成测试
│ └── textUtils.test.ts # 文本扩展名与行数统计测试
├── hooks/
│ ├── useDiff.test.ts # worker 化计算 hook(快路径/去抖/过期丢弃/回退/卸载清理)
│ ├── useDiff.ts
│ └── useDismiss.ts
├── components/
│ ├── ContextMenu.test.tsx # 右键菜单(含边缘防溢出)
│ ├── DiffView.test.tsx # 对比视图(渲染/滚动同步/右键/拖放)
│ ├── TextInputModal.test.tsx # 粘贴文本弹窗
│ └── Toolbar.test.tsx # 工具栏(选项/导航/导出菜单向上弹出/计算中禁用)
└── __tests__/
├── App.test.tsx # 应用集成级测试(加载/拖拽/粘贴/导出/容错/大输入回退)
└── main.test.ts # 入口挂载冒烟测试
约定:测试文件与被测文件同目录(
*.test.ts(x)),或集中放各模块下__tests__。
5. 覆盖重点与用例
5.1 diff 引擎(diffEngine.ts)— 最高优先级
- 空文本 / 空对非空(全新增)
- 完全一致 → 全部
unchanged,无差异 - 行级:新增、删除(含左/右行号、空槽 lineNo 为
null) - 词级:同一删除/新增配对为
modified并产生左右segs - 忽略选项:
ignoreCase、trimWhitespace、ignoreBlankLines生效与关闭 - 超长行防护:任一侧超过阈值跳过词级高亮(segs 为 null),行仍为 modified;边界长度仍产生 segs
- 行切分:结尾换行不产生多余空行
5.2 报告生成(report.ts)
- HTML:输出合法文档;Hero 区含人话结论(verdict)、文件卡片、统计卡与图例;差异分块(hunk-head)与块内行渲染;多块时输出目录锚点(toc/href="#seg-N"),单块不输出;相同内容段折叠(details/summary)且折叠段内保留全量行数据;一致场景 verdict ok;两侧空内容提示
- 纯文本:含增删改标记(
+ -)、行号按最大位数右对齐、头部人话结论 - Markdown:表格化、管道符转义保持表格结构、引用块含人话结论
- 差异分块(
buildSegments):空行集 / 无变更单段全展示 / 上下文 3 行与边界收敛 / 相邻区间合并 / 远距分两段省略数正确 / 自定义 context - 人话总结(
plainSummary):无差异一致结论 / 为 0 项省略 / 三类齐全完整罗列 - 格式分发与扩展名映射(
REPORT_EXT)
5.3 文本工具(textUtils.ts)
- 文本扩展名白名单放行 / 拒绝 / 大小写不敏感
countLines与 diff 引擎切分规则一致(结尾换行、CRLF)displayCols半角 1 列 / 全角 2 列 / 中英混排叠加 / 传 cap 时达上限提前返回
5.4 对比视图(DiffView.tsx)
- 渲染:行内容、行号、词级高亮段、行尾空白标注
- 虚拟滚动:大行数下仅渲染可见窗口(DOM 行数远小于总量);滚动后窗口移动;容器总高度按全部行数撑满
- 内容最小宽度:探针测得字符宽后按最大列宽换算 minWidth(半角/全角列宽,超长行封顶);探针未测得时不设置
- 折叠提示行:默认文案与自定义文案(仅看差异视图)
- 交互:左右/横向滚动同步、右键菜单回调、拖放回调、导航定位走受控
scrollTo
5.5 应用冒烟与集成(App.tsx)
- 渲染应用名
DiffLens;未加载文件时展示左右空态面板、不显示导出入口 - 加载文件后的对比视图、导出、右键菜单、拖拽、粘贴、容错提示
- 仅看差异视图:未更改行折叠、折叠提示出现、关闭后恢复
- F7 / Shift+F7 导航快捷键;粘贴弹窗打开时快捷键不抢占
- 交换左右侧后面板文件互换
- 大输入(超快路径阈值)在无 Worker 环境去抖到期后回退同步计算,完成后无计算中遮罩
5.6 diff 计算 worker 化(useDiff.ts / createDiffWorker.ts)
- 快路径:两侧总行数不超过 2000 时同步计算,不创建 worker,结果与 computeDiff 一致
- 重路径:进入 computing 且 diff 置空;200ms 去抖到期后才创建 worker 并派发;响应按 jobId 匹配,错误/过期 jobId 被丢弃
- 输入变更:已派发的旧 worker 终止重建(等价取消);去抖期内变更则旧任务未创建即取消(零创建与计算开销)
- worker 不可用(环境缺失/工厂返回 null):去抖到期后主线程同步回退
- 卸载:去抖期内卸载则 worker 从未创建;去抖到期后卸载则终止 worker,去抖定时器均被清理
- 工厂:无 Worker 环境返回 null;可用环境返回实例
6. 运行命令
npm test # 运行全部测试(CI / 提交前)
npm run test:watch # 监听模式,开发中用
7. 质量门禁
提交与推送前 必须全部通过:
npm run typecheck
npm test
npm run build
任一失败即禁止提交;修复通过后再提交发布。
8. 覆盖率目标(演进基线)
| 模块 | 目标 |
|---|---|
| 逻辑层(diff / report / textUtils) | 行覆盖 ≥ 80% |
| 组件层(components / App) | 覆盖主流程空态与关键交互 |
80% 四项阈值(statements / branches / functions / lines)已写入
vitest.config.ts的coverage.thresholds,作为 CI 硬门禁强制执行,未达标即测试失败。
9. 演进方向(后续迭代)
- 接入 Playwright 对打包后的 Electron 应用做端到端验收
- 对 IPC 层(open / decode / save-report)补充集成测试
- 大文件性能基准测试(虚拟滚动落地后)
© 2026 MetonaTeam · thzxx · DiffLens