Files
DiffLens/docs/测试策略与方案.md
T

162 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 # 全局 setupjest-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:输出合法文档、含文件名/统计/类型高亮语义
- 纯文本:含增删改标记(`+ -`)、行号按最大位数右对齐
- Markdown:表格化、管道符转义保持表格结构
- 格式分发与扩展名映射(`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. 运行命令
```bash
npm test # 运行全部测试(CI / 提交前)
npm run test:watch # 监听模式,开发中用
```
---
## 7. 质量门禁
提交与推送前 **必须全部通过**
```bash
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