# 自动化测试方案讨论 ## 需求背景 `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. 能为横竖屏、书签、搜索和后续阅读增强功能提供稳定回归基础