# 图像注释保存与重现功能测试方案 ## 文档信息 - **测试方案版本**: 1.0 - **创建日期**: 2025-12-16 - **最后更新**: 2025-12-16 - **相关需求文档**: [图像注释保存与重现功能需求](../需求/图像注释保存与重现功能需求.md) - **相关实现文档**: [保存注释功能实现文档](../实现/保存注释功能实现文档.md) --- ## 1. 测试概述 ### 1.1 测试目标 验证图像注释的创建、保存、加载、重现、编辑和删除功能,确保所有类型的注释工具都能正常工作,并且注释数据能够正确持久化和恢复。 ### 1.2 测试范围 - 所有注释工具的创建功能 - 注释自动保存机制 - 注释数据的加载和重现 - 注释编辑功能 - 注释删除功能 - 注释数据格式验证 - API调用验证 - Redux状态管理验证 ### 1.3 测试环境 - **浏览器**: Chrome 90+, Edge 90+, Firefox 88+ - **测试框架**: Cypress E2E - **Mock工具**: Cypress Intercept - **前端框架**: React + Redux Toolkit - **图像工具库**: Cornerstone Tools --- ## 2. 注释工具类型清单 基于实际代码 `src/pages/view/components/MeasurementPanel.tsx`,系统支持以下测量工具: ### 2.1 基础测量工具 | 工具名称 | 工具标识(action) | 图标名称 | 描述 | 优先级 | |---------|-----------------|---------|------|--------| | **线段测量** | 线段测量 | btn_LineMeasurement | 测量两点之间的直线距离 | P0 | | **角度测量** | 角度测量 | btn_AngleMeasurement | 测量三点形成的角度 | P0 | | **清除测量** | 清除测量 | btn_ClearMeasurement | 清除所有测量标记 | P0 | | **测量校正** | 测量校正 | MeasurementCalibration | 校正测量比例 | P1 | ### 2.2 专业测量工具 | 工具名称 | 工具标识(action) | 图标名称 | 描述 | 优先级 | |---------|-----------------|---------|------|--------| | **Cobb角** | Cobb角 | btn_Cobbangle | 脊柱侧弯角度测量 | P1 | ### 2.3 宠物专用测量工具 | 工具名称 | 工具标识(action) | 图标名称 | 描述 | 优先级 | |---------|-----------------|---------|------|--------| | **髋臼水平角** | 髋臼水平角 | btn_DAR | 髋关节发育评估 | P1 | | **胫骨平台夹角** | 胫骨平台夹角 | btn_TPA | 膝关节角度测量 | P1 | | **髋关节牵引指数** | 髋关节牵引指数 | btn_HDI | 髋关节松弛度评估 | P1 | | **髋关节水平角** | 髋关节水平角 | btn_NHA | 髋关节角度测量 | P1 | | **心锥比** | 心锥比 | btn_VHS | 心脏大小评估 | P1 | | **胫骨平台骨切开术** | 胫骨平台骨切开术 | btn_TPLO | TPLO手术规划 | P2 | | **胫骨结节前移术** | 胫骨结节前移术 | btn_TTA | TTA手术规划 | P2 | | **胫骨结节前移术5点测量法** | 胫骨结节前移术5点测量法 | btn_TTA2 | TTA手术规划(5点法) | P2 | | **水平截骨术** | 水平截骨术 | btn_CBLO | CBLO手术规划 | P2 | | **股骨头覆盖率** | 股骨头覆盖率 | btn_DLS | 髋关节覆盖评估 | P2 | | **髋臼背覆盖** | 髋臼背覆盖 | btn_DAC | 髋关节覆盖评估 | P2 | | **拆线长度测量** | 拆线长度测量 | btn_FoldLine | 折线长度测量 | P1 | | **多边形长度测量** | 多边形长度测量 | btn_Polygon | 多边形周长测量 | P1 | | **找圆心** | 找圆心 | btn_CenterCircle | 定位圆形中心点 | P1 | | **找中线** | 找中线 | btn_CenterLine | 计算中线位置 | P1 | | **找中点** | 找中点 | btn_Midpoint | 计算线段中点 | P1 | | **直线垂直倾斜度** | 直线垂直倾斜度 | btn_VerticalInclination | 垂直倾斜角度 | P1 | | **直线水平倾斜度** | 直线水平倾斜度 | btn_HorizontalInclination | 水平倾斜角度 | P1 | | **矩形区域灰度** | 矩形区域灰度 | btn_RectangularGrayscale | 矩形区域灰度分析 | P1 | | **直线灰度** | 直线灰度 | btn_LineGrayscale | 直线灰度分布分析 | P1 | **工具总数**: 24个 (4个基础工具 + 1个专业工具 + 19个宠物专用工具) **注意**: 这些测量工具主要用于宠物医学影像分析,包括骨科手术规划、心脏评估、髋关节评估等专业应用场景。 --- ## 3. 测试套件设计 ### 测试套件 1: 注释创建功能测试 **文件路径**: `cypress/e2e/process/annotation-creation.cy.ts` #### TC-ANN-CREATE-01: 长度测量工具创建 **测试目标**: 验证LengthTool创建长度测量注释 **前置条件**: - 已登录系统 - 已打开图像处理页面 - 已加载测试图像 **测试步骤**: 1. 选择长度测量工具 2. 在图像上点击两个点创建测量线 3. 验证测量值实时显示 4. 验证注释保存API被调用 **验证点**: - ✅ 工具被正确激活 - ✅ 可以在图像上创建测量线 - ✅ 测量值正确显示(格式: "XX.X mm") - ✅ API调用: `POST /dr/api/v1/auth/image/{id}/annotation` - ✅ 请求体包含正确的toolName: "LengthTool" - ✅ 包含handles.points坐标数据 - ✅ 包含cachedStats.length测量结果 **Mock配置**: ```typescript cy.intercept('POST', '/dr/api/v1/auth/image/*/annotation', { statusCode: 200, body: { code: '0x000000', description: 'Success', data: {} } }).as('saveAnnotation'); ``` **优先级**: P0 (高) --- #### TC-ANN-CREATE-02: 角度测量工具创建 **测试目标**: 验证AngleTool创建角度测量注释 **前置条件**: 同TC-ANN-CREATE-01 **测试步骤**: 1. 选择角度测量工具 2. 在图像上点击三个点创建角度测量 3. 验证角度值实时显示 4. 验证注释保存API被调用 **验证点**: - ✅ 工具被正确激活 - ✅ 可以在图像上创建角度测量 - ✅ 角度值正确显示(格式: "XX.X°") - ✅ toolName: "AngleTool" - ✅ handles.points包含3个坐标点 - ✅ cachedStats.angle包含角度值 **优先级**: P0 (高) --- #### TC-ANN-CREATE-03: 文本标签工具创建 **测试目标**: 验证LabelTool创建文本标注 **前置条件**: 同TC-ANN-CREATE-01 **测试步骤**: 1. 选择文本标签工具 2. 在图像上点击位置 3. 输入文本内容: "测试标注" 4. 确认输入 5. 验证注释保存API被调用 **验证点**: - ✅ 工具被正确激活 - ✅ 可以在图像上放置文本标签 - ✅ 文本内容正确显示 - ✅ toolName: "LabelTool" - ✅ label字段包含文本内容 - ✅ handles.textBox包含文本框位置 **优先级**: P0 (高) --- #### TC-ANN-CREATE-04: Cobb角测量工具创建 **测试目标**: 验证Cobb角测量工具创建专业测量注释 **前置条件**: 同TC-ANN-CREATE-01 **测试步骤**: 1. 选择Cobb角测量工具 2. 按照工具要求标记脊柱关键点 3. 验证Cobb角度值自动计算并显示 4. 验证注释保存API被调用 **验证点**: - ✅ 工具被正确激活 - ✅ 可以标记所有必需的解剖点 - ✅ Cobb角度值正确计算并显示 - ✅ action: "Cobb角" - ✅ handles.points包含脊柱关键点 - ✅ cachedStats包含角度值 - ✅ 包含元数据: viewPlaneNormal, viewUp等 **优先级**: P1 (中) --- #### TC-ANN-CREATE-05: 宠物专用测量工具创建(髋关节水平角) **测试目标**: 验证宠物专用测量工具(以髋关节水平角为例)创建专业测量 **前置条件**: 同TC-ANN-CREATE-01 **测试步骤**: 1. 选择髋关节水平角测量工具 2. 按照工具要求标记关键解剖点 3. 验证角度值自动计算并显示 4. 验证注释保存API被调用 **验证点**: - ✅ 工具被正确激活 - ✅ 可以标记所有必需的解剖点 - ✅ 角度值正确计算并显示 - ✅ action: "髋关节水平角" - ✅ handles.points包含关键解剖点 - ✅ cachedStats包含测量结果 - ✅ 包含元数据: viewPlaneNormal, viewUp等 **优先级**: P1 (中) **注**: 其他宠物专用测量工具(如胫骨平台夹角、心锥比、矩形区域灰度等)的测试方法类似,主要验证: - 工具正确激活 - 关键点标记 - 测量结果计算 - 注释保存 --- ### 测试套件 2: 注释保存功能测试 **文件路径**: `cypress/e2e/process/annotation-save.cy.ts` #### TC-ANN-SAVE-01: 自动保存机制验证 **测试目标**: 验证注释创建后自动保存 **前置条件**: 同TC-ANN-CREATE-01 **测试步骤**: 1. 创建一个长度测量注释 2. 等待保存API调用 3. 验证API请求体数据格式 **验证点**: - ✅ 创建注释后1秒内触发保存API - ✅ API请求方法: POST - ✅ API路径: `/dr/api/v1/auth/image/{sopInstanceUid}/annotation` - ✅ 请求体为JSON格式 - ✅ 包含必需字段: id, toolName, sopInstanceUid, handles, metadata - ✅ 包含时间戳: createdAt, updatedAt **优先级**: P0 (高) --- #### TC-ANN-SAVE-02: 防抖保存机制 **测试目标**: 验证编辑注释时的防抖保存 **前置条件**: 已创建一个注释 **测试步骤**: 1. 拖拽注释手柄修改位置 2. 连续快速拖拽多次 3. 验证保存API调用次数 **验证点**: - ✅ 连续修改不会立即保存 - ✅ 停止修改后1秒触发保存 - ✅ 只发送一次保存请求(防抖) - ✅ 请求体包含最新的修改数据 **优先级**: P0 (高) --- #### TC-ANN-SAVE-03: 批量保存优化 **测试目标**: 验证多个注释的批量保存 **前置条件**: 同TC-ANN-CREATE-01 **测试步骤**: 1. 快速创建3个不同类型的注释 2. 验证保存API调用 **验证点**: - ✅ 可以同时创建多个注释 - ✅ 保存请求合理优化(批量或防抖) - ✅ 所有注释数据都被保存 - ✅ 无重复保存请求 **优先级**: P1 (中) --- #### TC-ANN-SAVE-04: 保存失败处理 **测试目标**: 验证保存失败时的错误处理 **前置条件**: Mock保存API返回错误 **测试步骤**: 1. 创建一个注释 2. Mock API返回500错误 3. 验证错误处理机制 **验证点**: - ✅ 捕获API错误 - ✅ 显示错误提示(可选) - ✅ 注释数据保留在本地 - ✅ 用户可以重试保存 - ✅ Redux状态标记为保存失败 **Mock配置**: ```typescript cy.intercept('POST', '/dr/api/v1/auth/image/*/annotation', { statusCode: 500, body: { code: '0x000001', description: 'Internal Server Error' } }).as('saveAnnotationFail'); ``` **优先级**: P0 (高) --- ### 测试套件 3: 注释加载和重现功能测试 **文件路径**: `cypress/e2e/process/annotation-load.cy.ts` #### TC-ANN-LOAD-01: 自动加载注释 **测试目标**: 验证打开图像时自动加载注释 **前置条件**: - 已登录系统 - Mock注释数据 **测试步骤**: 1. 打开图像处理页面 2. 验证加载注释API被调用 3. 验证注释显示在图像上 **验证点**: - ✅ 图像加载完成后立即调用获取注释API - ✅ API路径: `GET /dr/api/v1/auth/image/{sopInstanceUid}/annotation` - ✅ 返回的注释数据被正确解析 - ✅ 所有注释显示在图像上 - ✅ 注释位置准确 - ✅ 测量值正确显示 **Mock数据示例**: ```json { "code": "0x000000", "description": "Success", "data": [ { "id": "ann-001", "toolName": "LengthTool", "sopInstanceUid": "1.2.3.4.5", "handles": { "points": [ {"x": 100, "y": 100, "z": 0}, {"x": 200, "y": 200, "z": 0} ] }, "metadata": { "viewPlaneNormal": [0, 0, 1], "viewUp": [0, -1, 0], "FrameOfReferenceUID": "1.2.3", "referencedImageId": "image-1" }, "cachedStats": { "length": 141.42 }, "createdAt": "2025-12-16T10:00:00Z", "updatedAt": "2025-12-16T10:00:00Z" } ] } ``` **优先级**: P0 (高) --- #### TC-ANN-LOAD-02: 加载多个注释 **测试目标**: 验证同时加载多个不同类型的注释 **前置条件**: Mock包含3个不同类型注释的数据 **测试步骤**: 1. 打开图像 2. 验证所有注释都被加载和显示 **验证点**: - ✅ 所有类型的注释都能正确加载 - ✅ LengthTool注释正确显示 - ✅ AngleTool注释正确显示 - ✅ LabelTool注释正确显示 - ✅ 注释顺序与数据顺序一致 - ✅ 不同注释互不干扰 **优先级**: P0 (高) --- #### TC-ANN-LOAD-03: 空注释数据处理 **测试目标**: 验证图像无注释时的处理 **前置条件**: Mock返回空注释列表 **测试步骤**: 1. 打开图像 2. 验证处理空数据的逻辑 **验证点**: - ✅ API返回空数组不报错 - ✅ 图像正常显示 - ✅ 无注释显示在图像上 - ✅ 用户可以创建新注释 **Mock配置**: ```typescript cy.intercept('GET', '/dr/api/v1/auth/image/*/annotation', { statusCode: 200, body: { code: '0x000000', description: 'Success', data: [] } }).as('getEmptyAnnotations'); ``` **优先级**: P1 (中) --- #### TC-ANN-LOAD-04: 加载失败处理 **测试目标**: 验证加载注释失败时的处理 **前置条件**: Mock API返回错误 **测试步骤**: 1. 打开图像 2. Mock API返回500错误 3. 验证错误处理 **验证点**: - ✅ 捕获API错误 - ✅ 图像仍然正常显示 - ✅ 显示错误提示(可选) - ✅ 用户可以重试加载 - ✅ 不影响其他功能 **优先级**: P1 (中) --- #### TC-ANN-LOAD-05: 注释数据验证 **测试目标**: 验证加载的注释数据格式验证 **前置条件**: Mock包含格式错误的注释数据 **测试步骤**: 1. Mock返回缺少必需字段的注释 2. 验证数据验证机制 **验证点**: - ✅ 识别数据格式错误 - ✅ 跳过无效注释 - ✅ 继续加载有效注释 - ✅ 记录错误日志 - ✅ 不崩溃或阻塞 **优先级**: P1 (中) --- ### 测试套件 4: 注释编辑功能测试 **文件路径**: `cypress/e2e/process/annotation-edit.cy.ts` #### TC-ANN-EDIT-01: 拖拽修改注释位置 **测试目标**: 验证通过拖拽手柄修改注释 **前置条件**: 已加载包含注释的图像 **测试步骤**: 1. 选择一个长度测量注释 2. 拖拽手柄修改端点位置 3. 验证测量值更新 4. 验证保存API被调用 **验证点**: - ✅ 可以选中注释 - ✅ 手柄可拖拽 - ✅ 测量值实时更新 - ✅ 触发保存API(防抖) - ✅ 新位置数据正确保存 **优先级**: P0 (高) --- #### TC-ANN-EDIT-02: 修改文本标签内容 **测试目标**: 验证修改文本标注的内容 **前置条件**: 已加载包含文本标注的图像 **测试步骤**: 1. 双击文本标注 2. 修改文本内容 3. 确认修改 4. 验证保存API被调用 **验证点**: - ✅ 可以编辑文本内容 - ✅ 文本立即更新显示 - ✅ 触发保存API - ✅ 新文本内容正确保存 **优先级**: P0 (高) --- #### TC-ANN-EDIT-03: 并发编辑冲突处理 **测试目标**: 验证多用户编辑冲突的处理 **前置条件**: Mock服务器返回版本冲突 **测试步骤**: 1. 修改一个注释 2. Mock服务器返回版本冲突错误 3. 验证冲突处理机制 **验证点**: - ✅ 检测到版本冲突 - ✅ 提示用户冲突情况 - ✅ 提供冲突解决选项(可选) - ✅ 防止数据丢失 **优先级**: P2 (低) --- ### 测试套件 5: 注释删除功能测试 **文件路径**: `cypress/e2e/process/annotation-delete.cy.ts` #### TC-ANN-DELETE-01: 单个注释删除 **测试目标**: 验证删除单个注释 **前置条件**: 已加载包含注释的图像 **测试步骤**: 1. 选中一个注释 2. 按Delete键或点击删除按钮 3. 确认删除(如有提示) 4. 验证注释被删除 **验证点**: - ✅ 可以选中注释 - ✅ 删除操作生效 - ✅ 注释从图像上消失 - ✅ 调用删除API(如果是已保存的注释) - ✅ Redux状态更新 **优先级**: P0 (高) --- #### TC-ANN-DELETE-02: 批量删除注释 **测试目标**: 验证批量删除多个注释 **前置条件**: 已加载包含多个注释的图像 **测试步骤**: 1. 选择多个注释(Ctrl+点击) 2. 执行批量删除 3. 验证所有选中的注释被删除 **验证点**: - ✅ 可以多选注释 - ✅ 批量删除生效 - ✅ 所有选中注释被删除 - ✅ 未选中注释保留 - ✅ 批量调用删除API或单次批量删除 **优先级**: P1 (中) --- #### TC-ANN-DELETE-03: 删除确认提示 **测试目标**: 验证删除确认对话框 **前置条件**: 配置启用删除确认 **测试步骤**: 1. 尝试删除注释 2. 验证弹出确认对话框 3. 点击取消 4. 验证注释未被删除 5. 再次删除并确认 6. 验证注释被删除 **验证点**: - ✅ 删除前显示确认对话框 - ✅ 取消操作保留注释 - ✅ 确认操作删除注释 - ✅ 对话框文本清晰明确 **优先级**: P1 (中) --- ### 测试套件 6: 数据格式和API测试 **文件路径**: `cypress/e2e/process/annotation-api.cy.ts` #### TC-ANN-API-01: 保存API请求格式验证 **测试目标**: 验证保存注释的API请求格式 **前置条件**: 已创建注释 **测试步骤**: 1. 拦截保存API请求 2. 验证请求格式 **验证点**: - ✅ 请求方法: POST - ✅ Content-Type: application/json - ✅ 请求体包含所有必需字段 - ✅ sopInstanceUid正确 - ✅ toolName正确 - ✅ handles数据格式正确 - ✅ metadata数据格式正确 - ✅ 时间戳格式正确(ISO 8601) **优先级**: P0 (高) --- #### TC-ANN-API-02: 获取API响应格式验证 **测试目标**: 验证获取注释的API响应处理 **前置条件**: Mock正确格式的响应 **测试步骤**: 1. 打开图像触发获取API 2. 验证响应数据处理 **验证点**: - ✅ 正确解析响应JSON - ✅ 正确处理data数组 - ✅ 正确反序列化注释对象 - ✅ 坐标数据正确转换 - ✅ 元数据正确恢复 **优先级**: P0 (高) --- #### TC-ANN-API-03: API错误码处理 **测试目标**: 验证各种API错误码的处理 **前置条件**: Mock不同错误响应 **测试步骤**: 1. Mock不同错误码(401, 403, 404, 500等) 2. 验证错误处理逻辑 **验证点**: - ✅ 401: 提示重新登录 - ✅ 403: 提示权限不足 - ✅ 404: 提示资源不存在 - ✅ 500: 提示服务器错误 - ✅ 网络错误: 提示网络问题 - ✅ 所有错误都有用户友好提示 **优先级**: P1 (中) --- ### 测试套件 7: 性能和边界测试 **文件路径**: `cypress/e2e/process/annotation-performance.cy.ts` #### TC-ANN-PERF-01: 大量注释加载性能 **测试目标**: 验证加载大量注释时的性能 **前置条件**: Mock包含100个注释的数据 **测试步骤**: 1. 打开包含100个注释的图像 2. 测量加载和渲染时间 **验证点**: - ✅ 加载时间 < 3秒 - ✅ 所有注释正确显示 - ✅ UI不卡顿 - ✅ 内存使用合理 **优先级**: P1 (中) --- #### TC-ANN-PERF-02: 注释数据大小限制 **测试目标**: 验证注释数据大小限制 **前置条件**: 尝试创建超大注释 **测试步骤**: 1. 创建包含大量坐标点的注释 2. 验证大小限制机制 **验证点**: - ✅ 单个注释 < 100KB - ✅ 超过限制时提示用户 - ✅ 防止创建过大的注释 **优先级**: P2 (低) --- #### TC-ANN-PERF-03: 并发操作性能 **测试目标**: 验证快速连续操作的性能 **前置条件**: 已加载图像 **测试步骤**: 1. 快速连续创建多个注释 2. 快速连续修改注释 3. 验证系统响应 **验证点**: - ✅ 操作响应及时 - ✅ 防抖机制有效 - ✅ 不会重复保存 - ✅ UI保持流畅 **优先级**: P1 (中) --- ## 4. 测试数据准备 ### 4.1 Mock注释数据模板 #### 长度测量注释 ```json { "id": "length-001", "toolName": "LengthTool", "sopInstanceUid": "1.2.840.10008.5.1.4.1.1.2.1", "handles": { "points": [ {"x": 100, "y": 100, "z": 0}, {"x": 200, "y": 200, "z": 0} ] }, "metadata": { "viewPlaneNormal": [0, 0, 1], "viewUp": [0, -1, 0], "FrameOfReferenceUID": "1.2.3.4.5", "referencedImageId": "wadouri:http://example.com/image.dcm" }, "cachedStats": { "length": 141.42 }, "label": "Length Measurement", "createdAt": "2025-12-16T10:00:00.000Z", "updatedAt": "2025-12-16T10:00:00.000Z", "userId": "user-001" } ``` #### 角度测量注释 ```json { "id": "angle-001", "toolName": "AngleTool", "sopInstanceUid": "1.2.840.10008.5.1.4.1.1.2.1", "handles": { "points": [ {"x": 100, "y": 100, "z": 0}, {"x": 150, "y": 150, "z": 0}, {"x": 200, "y": 100, "z": 0} ] }, "metadata": { "viewPlaneNormal": [0, 0, 1], "viewUp": [0, -1, 0], "FrameOfReferenceUID": "1.2.3.4.5", "referencedImageId": "wadouri:http://example.com/image.dcm" }, "cachedStats": { "angle": 90.0 }, "label": "Angle Measurement", "createdAt": "2025-12-16T10:01:00.000Z", "updatedAt": "2025-12-16T10:01:00.000Z", "userId": "user-001" } ``` #### 文本标注 ```json { "id": "label-001", "toolName": "LabelTool", "sopInstanceUid": "1.2.840.10008.5.1.4.1.1.2.1", "handles": { "points": [ {"x": 150, "y": 150, "z": 0} ], "textBox": {"x": 160, "y": 150} }, "metadata": { "viewPlaneNormal": [0, 0, 1], "viewUp": [0, -1, 0], "FrameOfReferenceUID": "1.2.3.4.5", "referencedImageId": "wadouri:http://example.com/image.dcm" }, "label": "疑似结节", "createdAt": "2025-12-16T10:02:00.000Z", "updatedAt": "2025-12-16T10:02:00.000Z", "userId": "user-001" } ``` ### 4.2 Mock Handlers #### 文件: `cypress/support/mock/handlers/annotation.ts` ```typescript /** * Mock获取注释成功 */ export const mockGetAnnotationsSuccess = (annotations: any[]) => { cy.intercept('GET', '/dr/api/v1/auth/image/*/annotation', { statusCode: 200, body: { code: '0x000000', description: 'Success', data: annotations } }).as('getAnnotations'); }; /** * Mock保存注释成功 */ export const mockSaveAnnotationSuccess = () => { cy.intercept('POST', '/dr/api/v1/auth/image/*/annotation', { statusCode: 200, body: { code: '0x000000', description: 'Success', data: {} } }).as('saveAnnotation'); }; /** * Mock删除注释成功 */ export const mockDeleteAnnotationSuccess = () => { cy.intercept('DELETE', '/dr/api/v1/auth/image/*/annotation/*', { statusCode: 200, body: { code: '0x000000', description: 'Success', data: {} } }).as('deleteAnnotation'); }; /** * Mock API失败 */ export const mockAnnotationAPIFail = (statusCode: number = 500) => { cy.intercept('**/annotation**', { statusCode: statusCode, body: { code: '0x000001', description: 'Internal Server Error' } }).as('annotationAPIFail'); }; ``` --- ## 5. Page Object Model ### ProcessPage扩展 **文件**: `cypress/support/pageObjects/ProcessPage.ts` ```typescript class ProcessPage { // 工具选择 selectLengthTool() { cy.get('[data-testid="length-tool-btn"]').click(); } selectAngleTool() { cy.get('[data-testid="angle-tool-btn"]').click(); } selectLabelTool() { cy.get('[data-testid="label-tool-btn"]').click(); } selectAreaTool() { cy.get('[data-testid="area-tool-btn"]').click(); } // 注释操作 createLengthAnnotation(point1: {x: number, y: number}, point2: {x: number, y: number}) { this.selectLengthTool(); cy.get('.viewport-canvas').click(point1.x, point1.y); cy.get('.viewport-canvas').click(point2.x, point2.y); } createAngleAnnotation( point1: {x: number, y: number}, point2: {x: number, y: number}, point3: {x: number, y: number} ) { this.selectAngleTool(); cy.get('.viewport-canvas').click(point1.x, point1.y); cy.get('.viewport-canvas').click(point2.x, point2.y); cy.get('.viewport-canvas').click(point3.x, point3.y); } createLabelAnnotation(position: {x: number, y: number}, text: string) { this.selectLabelTool(); cy.get('.viewport-canvas').click(position.x, position.y); cy.get('input[type="text"]').type(text); cy.get('input[type="text"]').type('{enter}'); } // 验证注释显示 verifyAnnotationVisible(toolName: string) { cy.get(`.annotation-${toolName.toLowerCase()}`).should('be.visible'); } verifyMeasurementValue(value: string) { cy.get('.measurement-value').should('contain', value); } // 注释编辑 selectAnnotation(annotationId: string) { cy.get(`[data-annotation-id="${annotationId}"]`).click(); } deleteSelectedAnnotation() { cy.get('body').type('{del}'); } // Redux状态验证 verifyAnnotationInStore(annotationId: string) { cy.window().its('store').invoke('getState') .its('annotations').its('list') .should('contain', annotationId); } // API调用验证 waitForSaveAnnotation() { cy.wait('@saveAnnotation'); } waitForLoadAnnotations() { cy.wait('@getAnnotations'); } verifyAnnotationCount(count: number) { cy.get('.annotation-item').should('have.length', count); } } export default ProcessPage; ``` --- ## 6. 测试执行计划 ### 第一阶段: 核心功能测试 (优先级: P0) **时间**: 3-4天 1. ✅ TC-ANN-CREATE-01: 长度测量工具创建 2. ✅ TC-ANN-CREATE-02: 角度测量工具创建 3. ✅ TC-ANN-CREATE-03: 文本标签工具创建 4. ✅ TC-ANN-SAVE-01: 自动保存机制 5. ✅ TC-ANN-SAVE-02: 防抖保存机制 6. ✅ TC-ANN-SAVE-04: 保存失败处理 7. ✅ TC-ANN-LOAD-01: 自动加载注释 8. ✅ TC-ANN-LOAD-02: 加载多个注释 9. ✅ TC-ANN-EDIT-01: 拖拽修改注释 10. ✅ TC-ANN-EDIT-02: 修改文本内容 11. ✅ TC-ANN-DELETE-01: 单个注释删除 12. ✅ TC-ANN-API-01: 保存API格式验证 13. ✅ TC-ANN-API-02: 获取API响应验证 ### 第二阶段: 扩展功能测试 (优先级: P1) **时间**: 2-3天 14. ✅ TC-ANN-CREATE-04: 面积测量工具 15. ✅ TC-ANN-CREATE-05: 髋关节角度测量 16. ✅ TC-ANN-SAVE-03: 批量保存优化 17. ✅ TC-ANN-LOAD-03: 空注释数据处理 18. ✅ TC-ANN-LOAD-04: 加载失败处理 19. ✅ TC-ANN-LOAD-05: 数据验证 20. ✅ TC-ANN-DELETE-02: 批量删除 21. ✅ TC-ANN-DELETE-03: 删除确认 22. ✅ TC-ANN-API-03: 错误码处理 23. ✅ TC-ANN-PERF-01: 大量注释性能 24. ✅ TC-ANN-PERF-03: 并发操作性能 ### 第三阶段: 边界和优化测试 (优先级: P2) **时间**: 1-2天 25. ✅ TC-ANN-EDIT-03: 并发编辑冲突 26. ✅ TC-ANN-PERF-02: 数据大小限制 27. 浏览器兼容性测试 28. 性能基准测试 --- ## 7. 测试覆盖率目标 - **功能覆盖**: 100% - 所有注释类型和操作 - **场景覆盖**: - 正常场景: 100% - 边界场景: 90%+ - 异常场景: 85%+ - **API覆盖**: 100% - 所有注释相关API - **工具覆盖**: 100% - 所有24种测量工具 --- ## 8. 验收标准 ### 8.1 功能验收 - [ ] 所有P0测试用例通过 (100%) - [ ] 至少90%的P1测试用例通过 - [ ] 所有注释工具可正常创建注释 - [ ] 注释保存和加载功能稳定 - [ ] 注释编辑和删除功能正常 - [ ] API调用格式正确 ### 8.2 性能验收 - [ ] 单个注释创建响应时间 < 100ms - [ ] 注释保存时间 < 1s - [ ] 加载50个注释 < 1s - [ ] 加载200个注释 < 5s - [ ] UI操作流畅,无明显卡顿 ### 8.3 稳定性验收 - [ ] 所有测试用例可重复执行 - [ ] 无随机失败的测试 - [ ] 错误处理机制完善 - [ ] 无内存泄漏 - [ ] 长时间运行稳定 ### 8.4 用户体验验收 - [ ] 工具选择直观 - [ ] 注释创建流畅 - [ ] 测量值准确显示 - [ ] 错误提示清晰 - [ ] 操作可撤销(如适用) --- ## 9. 风险评估 ### 9.1 技术风险 | 风险项 | 影响 | 概率 | 缓解措施 | |--------|------|------|----------| | Cornerstone Tools集成问题 | 高 | 中 | 深入学习Cornerstone API,准备降级方案 | | 坐标系转换错误 | 高 | 中 | 详细测试各种图像类型,验证坐标精度 | | 大数据量性能问题 | 中 | 中 | 实现虚拟化渲染,分批加载 | | 浏览器兼容性问题 | 中 | 低 | 多浏览器测试,使用polyfill | ### 9.2 业务风险 | 风险项 | 影响 | 概率 | 缓解措施 | |--------|------|------|----------| | 需求变更 | 中 | 中 | 模块化设计,易于扩展 | | 用户接受度低 | 中 | 低 | 用户测试,收集反馈 | | 数据丢失 | 高 | 低 | 实现本地缓存,离线支持 | --- ## 10. 测试环境搭建 ### 10.1 依赖的Mock Handlers 1. **用户认证**: mockLoginSuccess() 2. **国际化**: mockI18nSuccess() 3. **配额**: mockQuotaCheck() 4. **图像加载**: mockImageLoad() 5. **注释API**: mockGetAnnotationsSuccess(), mockSaveAnnotationSuccess() ### 10.2 测试数据要求 - 至少3种不同类型的注释数据 - 包含正常、边界、异常情况的数据 - 足够的数据量进行性能测试 ### 10.3 环境配置 ```typescript // cypress.config.ts export default { e2e: { baseUrl: 'http://localhost:3000', viewportWidth: 1920, viewportHeight: 1080, video: false, defaultCommandTimeout: 10000 } }; ``` --- ## 11. 测试执行指南 ### 11.1 运行所有注释测试 ```bash npx cypress run --spec "cypress/e2e/process/annotation-*.cy.ts" ``` ### 11.2 运行特定测试套件 ```bash # 创建功能测试 npx cypress run --spec "cypress/e2e/process/annotation-creation.cy.ts" # 保存功能测试 npx cypress run --spec "cypress/e2e/process/annotation-save.cy.ts" # 加载功能测试 npx cypress run --spec "cypress/e2e/process/annotation-load.cy.ts" ``` ### 11.3 在Cypress UI中运行 ```bash npx cypress open ``` 然后选择相应的测试文件。 --- ## 12. 测试报告 ### 12.1 测试结果记录表 | 测试套件 | 用例总数 | 通过 | 失败 | 跳过 | 通过率 | 执行时间 | |---------|---------|------|------|------|--------|----------| | 注释创建 | 5 | - | - | - | - | - | | 注释保存 | 4 | - | - | - | - | - | | 注释加载 | 5 | - | - | - | - | - | | 注释编辑 | 3 | - | - | - | - | - | | 注释删除 | 3 | - | - | - | - | - | | API测试 | 3 | - | - | - | - | - | | 性能测试 | 3 | - | - | - | - | - | | **总计** | **26** | **-** | **-** | **-** | **-** | **-** | ### 12.2 缺陷记录模板 ``` 缺陷ID: BUG-ANN-XXX 测试用例: TC-ANN-XXX 严重程度: Critical / Major / Minor 优先级: P0 / P1 / P2 复现步骤: 1. ... 2. ... 3. ... 实际结果: ... 预期结果: ... 附件: (截图/视频) ``` --- ## 13. 附录 ### A. 注释数据结构参考 ```typescript interface AnnotationData { // 基础信息 id: string; toolName: string; sopInstanceUid: string; // 几何数据 handles: { points: Point3[]; activeHandleIndex?: number; textBox?: Point2; }; // 元数据 metadata: { viewPlaneNormal: Point3; viewUp: Point3; FrameOfReferenceUID: string; referencedImageId: string; }; // 计算结果 cachedStats?: { length?: number; angle?: number; area?: number; }; // 显示属性 label?: string; highlighted?: boolean; isSelected?: boolean; // 时间戳 createdAt: string; updatedAt: string; userId?: string; } ``` ### B. API接口文档 #### 获取注释 **请求**: ``` GET /dr/api/v1/auth/image/{sopInstanceUid}/annotation ``` **响应**: ```json { "code": "0x000000", "description": "Success", "data": [AnnotationData] } ``` #### 保存注释 **请求**: ``` POST /dr/api/v1/auth/image/{sopInstanceUid}/annotation Content-Type: application/json AnnotationData ``` **响应**: ```json { "code": "0x000000", "description": "Success", "data": {} } ``` #### 删除注释 **请求**: ``` DELETE /dr/api/v1/auth/image/{sopInstanceUid}/annotation/{annotationId} ``` **响应**: ```json { "code": "0x000000", "description": "Success", "data": {} } ``` --- ## 文档版本 - **版本**: 1.0.0 - **创建日期**: 2025-12-16 - **最后更新**: 2025-12-16 - **作者**: Cline AI Assistant - **审核状态**: ⏳ 待审核 --- **测试方案状态**: ✅ 已完成