Files
ReadViewSDK/Doc/FeatureSolution/自动化测试方案讨论.md
T
2026-05-21 19:40:51 +08:00

419 lines
12 KiB
Markdown

# 自动化测试方案讨论
## 需求背景
`Doc/EPUB_MAINTENANCE.md` 已将“自动化测试”列为 EPUB 阅读器下一阶段的高优先级能力之一。
当前阅读器已经具备较完整的主链路能力,包括:
1. EPUB 解析与打开
2. WebView / DTCoreText / fixed-layout 三条正文渲染路径
3. 目录跳转、阅读位置恢复、主题与字号调整
4. 高亮、划线、批注、搜索等阅读交互能力
但这些能力目前主要依赖手工验证,缺少自动化回归保护。随着横竖屏切换、书签、更多搜索体验和阅读增强能力继续叠加,单靠人工回归会越来越难以稳定覆盖高联动场景。
因此,“自动化测试”这项需求的目标不是单纯增加几条测试用例,而是为 EPUB 阅读器建立一套可持续演进的自动化回归体系,优先保护以下核心链路:
1. 解析
2. 分页
3. 定位恢复
4. 目录跳转
5. 标注恢复
## 代码事实
### 已有基础
当前仓库并不是完全没有可测试的基础:
1. `Sources/RDReaderView/EPUBCore/` 已经把 parser、resourceResolver、location、readingSession、paginator 等能力拆成了相对独立的模块
2. `Sources/RDReaderView/EPUBTextRendering/` 已经将 DTCoreText 渲染、fragment 提取、富文本分页等逻辑收敛到明确的工具类型中
3. `RDEPUBLocation`、`RDEPUBHighlight`、TOC / spine / manifest 等模型本身适合做 deterministic 的断言
4. `ReadViewSDKDemo` 已经提供真实运行容器,后续可以承载 UI 自动化测试
结论:
1. 核心逻辑并非不可测
2. 更缺的是测试 target、测试夹具、断言策略和回归矩阵
### 当前实现存在的问题
#### 问题 1:工程里还没有测试承载层
从 `ReadViewSDKDemo.xcodeproj` 当前 target 配置来看,只有 `ReadViewSDKDemo` app target,没有独立的 `Tests` 或 `UITests` target。
这意味着当前并没有:
1. 用于跑 XCTest 的基础 target
2. 用于跑 XCUITest 的 UI 测试 target
3. 稳定的测试资源加载方式
#### 问题 2:关键链路缺少自动回归保护
当前高风险能力包括:
1. `RDEPUBParser` 解析 EPUB ZIP / OPF / spine / TOC
2. `RDEPUBResourceResolver.normalizedHref(_:)` 的路径标准化
3. `RDEPUBPaginator` 与 `RDEPUBTextPaginationSupport` 的分页结果
4. `RDEPUBReaderController.restoreLocation(_:)` 的定位恢复
5. 高亮 / 批注 persistence 的恢复链路
这些地方一旦回归,通常会表现为:
1. 打不开书
2. 目录跳错
3. 字号变化后位置飘移
4. 标注丢失或恢复失败
而这些问题都很适合被自动化测试尽早捕获。
#### 问题 3:如果直接从 UI 自动化起步,成本和脆弱性都偏高
EPUB 阅读器的很多问题发生在 UI 之下,例如:
1. TOC href 标准化错误
2. `fragment -> offset` 映射偏移
3. 分页结果为空或页数异常
4. `href + progression` 回落恢复逻辑不稳定
如果这些问题都等到 `XCUITest` 才暴露:
1. 定位根因会很慢
2. 测试执行时间会更长
3. 异步加载、动画、WebView 时序会让用例更脆
#### 问题 4:当前还没有固定的样书基线与测试夹具约定
要让自动化测试长期稳定,必须明确:
1. 哪几本样书是测试夹具
2. 每本样书用于验证哪种能力
3. 哪些断言可以依赖“页号”,哪些只能依赖 `href / fragment / progression`
如果没有这层约束,测试很容易随着样书变化或样式调整而频繁漂移。
## 需求拆解
建议把“自动化测试”需求拆成四部分,而不是把所有验证都堆到同一层。
### 1. 建立测试基础设施
先补齐可执行自动化测试的工程结构,包括:
1. `ReadViewSDKDemoTests`
2. `ReadViewSDKDemoUITests`
3. 样书 fixtures 目录
4. 统一的测试资源读取辅助工具
这是后续一切测试工作的前提。
### 2. 建立逻辑层 XCTest
这部分优先覆盖稳定、纯逻辑、可快速执行的能力:
1. parser 解析
2. href 标准化
3. TOC 路径映射
4. location / progression / fragment 相关转换
5. persistence 编解码
目标是让每次改动 parser、模型、定位和持久化逻辑时,都有快速反馈。
### 3. 建立集成层 XCTest
这部分不直接走 UI 自动化,但会驱动真实样书、真实分页和真实恢复链路,重点覆盖:
1. reflowable 样书分页
2. fixed-layout 样书页面模型生成
3. 字号变化后位置恢复
4. 目录跳转命中
5. 标注恢复
目标是把“阅读核心链路”在逻辑层和 UI 层之间补上一层更贴近真实运行的保护网。
### 4. 建立少量高价值 XCUITest
UI 自动化不追求全覆盖,而是做真实用户闭环的冒烟回归,例如:
1. 打开样书进入阅读器
2. 目录跳转
3. 调整字号
4. 创建高亮并重新进入验证恢复
5. 横竖屏切换后继续阅读
目标是证明“用户真的能完成关键操作”,而不是把所有细节都放进 UI 测试里。
## 技术路线对比
### 路线 A:优先建设 XCUITest
思路:
1. 先搭 UI 自动化
2. 用点击、滑动、旋转和断言可见文本的方式覆盖主要能力
优点:
1. 结果直观,容易贴近真实用户行为
2. 可以较快形成“端到端可用”的感知
风险:
1. 调试成本高
2. 受动画、异步、WebView 时序影响大
3. 很难快速判断问题出在 parser、分页还是 UI
4. 执行时间更长,不适合作为最早期主回归层
### 路线 B:优先建设 XCTest
思路:
1. 先为逻辑与集成层补单元测试
2. 把解析、分页、定位恢复等能力尽量在非 UI 层验证
优点:
1. 稳定性更高
2. 运行更快
3. 更利于问题定位
4. 更适合作为日常改动的主回归层
风险:
1. 不能完全证明 UI 交互链路没问题
2. 覆盖不到真实点击、WebView 手势和界面状态同步问题
### 路线 C:分层推进
思路:
1. 先建立测试基础设施
2. 以 XCTest 为主搭建核心保护网
3. 再补少量 XCUITest 做端到端闭环
优点:
1. 投入与收益平衡更好
2. 能优先保护最容易回归的核心能力
3. 既兼顾稳定性,也兼顾真实用户路径
风险:
1. 初期需要先设计测试层次和夹具约定
2. 需要控制 UI 测试范围,避免后续无节制膨胀
### 推荐结论
建议采用:
**主路线:路线 C,分层推进,XCTest 为主,XCUITest 为辅**
原因:
1. 当前最需要保护的是解析、分页、定位恢复这些高风险核心链路
2. 仓库当前还没有测试 target,先从更稳定的 XCTest 起步更合适
3. 少量 XCUITest 足以证明关键阅读流程可用,不必一开始追求全面 UI 覆盖
## 推荐方案
### 方案总览
自动化测试第一阶段建议形成如下结构:
```text
ReadViewSDKDemoTests
- ParserTests
- ResourceResolverTests
- LocationRestoreTests
- TextPaginationTests
- HighlightPersistenceTests
ReadViewSDKDemoUITests
- ReaderSmokeTests
- ReaderNavigationTests
- ReaderAnnotationTests
- ReaderRotationTests
```
同时建立一套最小样书夹具集:
1. `reflowable-basic.epub`
2. `fixed-layout-basic.epub`
3. `image-heavy.epub`
4. `toc-fragment.epub`
每本样书都应明确“它用来验证什么”,而不是仅作为示例文件存在。
### 关键改动建议
#### Task T1:建立测试 target 与基础资源加载能力
文件范围:
1. `ReadViewSDKDemo/ReadViewSDKDemo.xcodeproj`
2. 新增 `ReadViewSDKDemoTests/`
3. 新增 `ReadViewSDKDemoUITests/`
4. 新增测试夹具目录
改动:
1. 增加 unit test target
2. 增加 UI test target
3. 为测试 target 挂载样书与辅助资源
4. 提供统一 `TestBookLoader` / `FixtureLocator` 之类的测试辅助工具
完成定义:
1. 工程可以直接运行测试
2. 测试代码可以稳定读取样书资源
#### Task T2:补第一批逻辑层 XCTest
建议首批覆盖:
1. `RDEPUBParser` 能解析有效样书并产出非空 spine
2. `RDEPUBResourceResolver.normalizedHref(_:)` 能正确处理相对路径、父级路径和 fragment
3. TOC href 能统一映射到与 spine 一致的标准化路径
4. `RDEPUBHighlight` persistence 编解码结果一致
5. 定位模型在常见输入下不会丢 fragment 或 progression
完成定义:
1. parser / resolver / persistence / location 改动有自动回归保护
#### Task T3:补第一批集成层 XCTest
建议首批覆盖:
1. reflowable 样书分页结果非空
2. fixed-layout 样书能建立页模型
3. 字号变化后仍能按 `href + progression` 恢复到原章节附近
4. 目录跳转可命中预期 spine 资源
5. 高亮恢复后仍能定位到对应资源
完成定义:
1. 核心阅读链路具备非 UI 层的真实运行回归能力
#### Task T4:补第一批冒烟型 XCUITest
建议首批覆盖:
1. 打开样书并进入阅读器
2. 打开目录并跳转章节
3. 调整字号后继续阅读
4. 创建一条高亮并重进验证恢复
5. 横竖屏切换后继续阅读
完成定义:
1. 至少有一条真实用户闭环可以证明主功能未损坏
## 断言策略建议
为了降低测试漂移,建议统一以下断言原则:
### 1. 少依赖固定页号
页号非常容易受以下因素影响:
1. 字号
2. 行距
3. 视口尺寸
4. 图片加载时序
因此,自动化测试不应过度依赖“必须是第 N 页”这种断言。
### 2. 优先依赖稳定语义锚点
更推荐的断言对象包括:
1. `href`
2. `fragment`
3. `progression` 所在区间
4. spine index
5. 高亮所属资源
### 3. UI 测试只验证关键闭环
XCUITest 中更适合验证:
1. 页面是否成功进入
2. 关键按钮是否可操作
3. 操作后阅读器状态是否变化
4. 重进后状态是否可恢复
而不适合在 UI 测试中承载大量底层分页细节断言。
## 验收矩阵建议
自动化测试第一阶段至少要覆盖以下维度:
1. `webInteractive`
2. `webFixedLayout`
3. `textReflowable`
4. TOC 跳转
5. 字号变化后恢复
6. 高亮恢复
7. 横竖屏切换
8. 一到两本问题样书回归
如果资源有限,建议先保证“三条渲染路径 + 两条恢复链路”:
1. 三条渲染路径:`webInteractive` / `webFixedLayout` / `textReflowable`
2. 两条恢复链路:阅读位置恢复 / 标注恢复
## 风险与注意点
### 风险 1:测试一开始就绑定大量脆弱 UI 细节
如果测试过度依赖:
1. 动画时长
2. 可见文案位置
3. 某个具体页号
4. WebView 内即时渲染完成时机
后续维护成本会非常高。
### 风险 2:测试夹具过多但目标不清晰
样书数量不是越多越好。更重要的是:
1. 每本样书验证哪类能力
2. 哪些样书是主回归集
3. 哪些样书只在专项验证时使用
### 风险 3:横竖屏与字号变化断言过于绝对
这两类场景更适合验证:
1. 是否仍在同一章节或邻近语义位置
2. 是否仍保留原始 `href / fragment`
3. progression 是否在合理偏差范围内
而不适合验证“必须恢复到完全相同页号”。
## 推荐实施顺序
如果目标是“最小投入换最大稳定性提升”,建议按以下顺序推进:
1. 建立 `Tests` / `UITests` target
2. 补 parser / resolver / location / persistence 的 XCTest
3. 补分页、目录跳转、定位恢复的集成测试
4. 补 3 到 5 条高价值 XCUITest
5. 将横竖屏、问题样书和新增功能逐步并入回归矩阵
## 推荐结论
“自动化测试”这项需求,建议最终收敛为下面这句话:
**为 EPUB 阅读器建立一套分层自动化测试体系,以 XCTest 保护解析、分页、定位恢复、目录跳转和标注恢复等核心链路,再以少量 XCUITest 验证真实阅读闭环。**
这样做的好处是:
1. 能尽快为最容易回归的核心能力建立保护网
2. 不会过早陷入脆弱的全量 UI 自动化
3. 能为横竖屏、书签、搜索和后续阅读增强功能提供稳定回归基础