diff --git a/docs/07-端到端联动测试方案.md b/docs/07-端到端联动测试方案.md new file mode 100644 index 0000000..d042b71 --- /dev/null +++ b/docs/07-端到端联动测试方案.md @@ -0,0 +1,381 @@ +# 端到端联动测试方案 + +**版本:** v1.0 +**创建日期:** 2026-05-03 +**适用范围:** CNC机床数据采集系统 — 模拟器 + 采集服务 + 管理后台 + 数据库 全链路联动 + +--- + +## 一、测试环境准备(前置条件) + +| 组件 | 启动方式 | 验证方法 | +|------|---------|---------| +| **模拟器 CncSimulator** | `src\CncSimulator\bin\CncSimulator.exe` | 浏览器打开 `http://localhost:{port}/admin` 看到管理页面 | +| **采集服务 CncCollector** | `src\CncCollector\bin\CncCollector.exe` | `Invoke-WebRequest http://localhost:5800/api/collector/status` 返回 `isRunning:true` | +| **Web API (IIS)** | AppPool `haoliang` 已运行 | `Invoke-WebRequest http://127.0.0.1/api/admin/login` 返回200 | +| **数据库 MariaDB** | 服务已启动 | `mysql -u root -proot -e "SELECT COUNT(*) FROM cnc_business.cnc_machine"` | + +--- + +## 二、测试域A:模拟器测试 + +### A1. 模拟器基本功能 + +| # | 测试点 | 操作 | 期望结果 | 验证方法 | +|---|--------|------|---------|---------| +| A1.1 | 启动与数据输出 | 访问 `http://localhost:{port}/` | 返回JSON数组,包含在线设备数据 | PowerShell `Invoke-WebRequest`,验证JSON解析成功、数组>0 | +| A1.2 | 设备数据结构 | 解析返回JSON | 每台设备包含:`deviceCode, programName, partCount, runStatus, operateMode, spindleSpeedSet/Actual, feedSpeedSet/Actual, spindleLoad, machiningStatus` | 逐字段非空检查 | +| A1.3 | 管理页面 | 浏览器打开 `http://localhost:{port}/admin` | 显示HTML管理页面,设备列表、状态、操作按钮可见 | Playwright截图 | +| A1.4 | 状态API | GET `/admin/api/status` | 返回 `{name, port, isRunning, totalDevices, onlineDevices, ...}` | 字段非空 | + +### A2. 模拟器管理API + +| # | 测试点 | 操作 | 期望结果 | +|---|--------|------|---------| +| A2.1 | 停止模拟 | POST `/admin/api/stop` → 查status | `isRunning:false`,GET `/` 不再返回更新数据 | +| A2.2 | 启动模拟 | POST `/admin/api/start` → 查status | `isRunning:true`,数据恢复变化 | +| A2.3 | 修改数据频率 | POST `/admin/api/interval {value:5}` | status显示 `dataChangeInterval:5`,连续2次GET间隔5秒内数据变化 | +| A2.4 | 切换剧本模式 | POST `/admin/api/mode {mode:"manual"}` | status显示 `scenarioMode:"manual"`,设备不再自动切换场景 | +| A2.5 | 手动触发事件 | POST `/admin/api/event {deviceId:"xxx", eventType:"program_change"}` | 设备NC程序名变更,partCount可能重置 | +| A2.6 | 添加设备 | POST `/admin/api/add-device {deviceCode:"TEST-01", desc:"测试设备"}` | status设备数+1,新设备出现在GET `/` 响应中 | +| A2.7 | 移除设备 | POST `/admin/api/remove-device {deviceCode:"TEST-01"}` | status设备数-1,GET `/` 不再包含该设备 | + +### A3. 网络异常模拟 + +| # | 测试点 | 操作 | 期望结果 | +|---|--------|------|---------| +| A3.1 | HTTP 500 | POST `/admin/api/network {type:"http500"}` → 采集服务请求 | 模拟器返回500,采集服务记录失败 | +| A3.2 | 超时 | POST `/admin/api/network {type:"timeout"}` | 模拟器延迟60秒响应,采集服务超时 | +| A3.3 | 空数据 | POST `/admin/api/network {type:"empty"}` | 模拟器返回 `[]`,采集服务应记录空响应 | +| A3.4 | 畸形JSON | POST `/admin/api/network {type:"malformed"}` | 模拟器返回 `{broken`,采集服务应记录解析失败 | +| A3.5 | 拒绝连接 | POST `/admin/api/network {type:"refuse"}` | 端口不可达,采集服务应记录连接失败 | +| A3.6 | 恢复正常 | POST `/admin/api/network {type:"normal"}` | 模拟器恢复正常数据输出 | + +### A4. 模拟器数据统计 + +| # | 测试点 | 操作 | 期望结果 | +|---|--------|------|---------| +| A4.1 | 统计API | GET `/admin/api/stats` | `totalDevices, onlineDevices, totalParts, partsByDevice` 非空且合理 | +| A4.2 | 事件历史 | GET `/admin/api/event-history` | 返回事件数组,每条含 `timestamp, deviceCode, eventType, oldProgram, newProgram` | +| A4.3 | 完整汇总 | GET `/admin/api/full-summary` | 包含启动时间、运行时长、请求数、成功/失败数、每设备每程序零件数 | +| A4.4 | 错误日志 | 先设网络异常→恢复→GET `/admin/api/error-log` | 有对应错误记录,含 `errorType, description, affectedDevices` | +| A4.5 | 请求日志 | GET `/admin/api/logs` | 返回最近100条采集日志,每条含 `timestamp, deviceCount, keyData, fullJson` | + +--- + +## 三、测试域B:采集服务测试 + +### B1. 采集引擎启停 + +| # | 测试点 | 操作 | 期望结果 | 验证方法 | +|---|--------|------|---------|---------| +| B1.1 | 引擎启动 | POST `/api/collector/start` (带X-Api-Key) | 返回 `code:0`,status显示 `isRunning:true` | 调5800 status确认 | +| B1.2 | 重复启动 | 再次POST start | 静默返回成功(幂等) | status仍为running | +| B1.3 | 引擎停止 | POST `/api/collector/stop` | `isRunning:false`,心跳表最新记录status=stopped | 查DB | +| B1.4 | 启动后心跳立即写入 | POST start → 立即查心跳表 | 最新记录status=running,uptime_seconds=0 | `SELECT * FROM cnc_log.log_collector_heartbeat ORDER BY id DESC LIMIT 1` | + +### B2. 数据采集流程 + +| # | 测试点 | 操作 | 期望结果 | 验证方法 | +|---|--------|------|---------|---------| +| B2.1 | 正常采集 | 模拟器运行中,采集服务运行中,等待1-2个采集间隔 | `cnc_collect_record` 有新数据写入 | 查DB:`SELECT COUNT(*) FROM cnc_collect_record WHERE collect_time > NOW() - INTERVAL 1 MINUTE` | +| B2.2 | 原始JSON存储 | 同上 | `log_collect_raw` 有新记录,`raw_json` 字段非空 | 查DB | +| B2.3 | 采集记录字段完整 | 查最新采集记录 | `machine_id, collect_time, program_name, part_count, device_status, run_status, spindle_speed_set, spindle_speed_actual` 均非空 | 逐字段检查 | +| B2.4 | 设备状态更新 | 采集1-2轮后查 `cnc_machine` | `last_ping_time, last_collect_time, last_program_name, last_part_count, last_device_status, last_run_status` 更新 | 查DB | + +### B3. 生产段跟踪(ProductionTracker) + +| # | 测试点 | 操作 | 期望结果 | 验证方法 | +|---|--------|------|---------|---------| +| B3.1 | 新程序名创建段 | 模拟器切换NC程序(触发program_change事件) | `cnc_production_segment` 新增一条记录,`start_time` 有值,`end_time` 为NULL(活跃段) | 查DB | +| B3.2 | 程序切换结账 | 再次切换程序 | 上一段 `end_time` 填充,`quantity = end_part_count - start_part_count` | 查DB | +| B3.3 | 同程序多次出现 | 先O0001→O0002→O0001 | 两段O0001分别记录(分段记录) | 查DB,同日同机器有2条program_name=O0001 | + +### B4. 心跳与监控 + +| # | 测试点 | 操作 | 期望结果 | 验证方法 | +|---|--------|------|---------|---------| +| B4.1 | 定时心跳 | 等待2个心跳间隔(20秒) | 心跳表新增≥2条running记录 | 查DB | +| B4.2 | 停止后心跳 | POST stop | 最新心跳status=stopped | 查DB | +| B4.3 | 配置轮询 | 修改DB中运行时配置,等待1个轮询周期(30秒) | 日志输出配置刷新信息 | 查看采集服务控制台/log | + +### B5. 异常处理 + +| # | 测试点 | 操作 | 期望结果 | 验证方法 | +|---|--------|------|---------|---------| +| B5.1 | 采集地址不可达 | 停止模拟器 → 等待采集 | `log_collect_raw` 记录失败,`is_success=0`,`error_message` 非空 | 查DB | +| B5.2 | 采集地址恢复 | 重启模拟器 | 采集恢复,`is_success=1` | 查DB | +| B5.3 | 空数据处理 | 模拟器返回空数组 | 采集不崩溃,日志记录空响应 | 查采集服务日志 | +| B5.4 | 畸形JSON处理 | 模拟器返回畸形JSON | 采集不崩溃,记录解析错误 | 查采集服务日志 | +| B5.5 | 连续失败告警 | 模拟器持续返回500,超过阈值(默认5次) | 告警触发 | 查 `cnc_alert` 或日志 | + +### B6. 配置刷新 + +| # | 测试点 | 操作 | 期望结果 | 验证方法 | +|---|--------|------|---------|---------| +| B6.1 | 手动刷新 | POST `/api/collector/refresh` | 返回成功,日志输出配置刷新 | 查日志 | +| B6.2 | 新增采集地址 | DB中新增一条 `cnc_collect_address` → refresh | status中workerCount+1 | 调status确认 | +| B6.3 | 删除采集地址 | DB中删除/禁用一条地址 → refresh | status中workerCount-1 | 调status确认 | + +--- + +## 四、测试域C:管理后台功能测试 + +> 每个测试点对应的维度编号参照 `docs/06-测试规范.md` 5.0维度总表。 + +### C1. 登录(/login) + +| # | 测试点 | 期望结果 | 维度 | +|---|--------|---------|------| +| C1.1 | 正确账密登录(admin/admin123) | 跳转到仪表盘,localStorage有token | 1 | +| C1.2 | 错误密码 | 提示错误,停留在登录页 | 20 | +| C1.3 | 无Token访问管理后台 | 重定向到/login | 20 | +| C1.4 | 有Token访问/login | 重定向到/dashboard | 20 | + +### C2. 仪表盘(/dashboard) + +| # | 测试点 | 期望结果 | 维度 | +|---|--------|---------|------| +| C2.1 | 8个统计卡片有值 | 每个卡片数值≠空≠占位符 | 3 | +| C2.2 | 采集服务状态显示 | 显示"运行中"或"已停止",对应按钮可操作 | 23 | +| C2.3 | 机床状态分布图表 | 饼图/柱状图有渲染内容(非空白) | 3.1 | +| C2.4 | 产量趋势图表 | 折线图有数据点 | 3.1 | +| C2.5 | 机床/工人排行表格 | 行数>0,每列有值 | 4,5 | +| C2.6 | 最新告警列表 | ≥0条(有则检查字段非空) | 4,5 | +| C2.7 | 日期筛选 | 切换日期→趋势/排行数据变化 | 12 | +| C2.8 | API vs 页面对账 | 调API → 对比卡片数值一致 | 17 | +| C2.9 | 启动采集按钮 | 点击→状态切换为"运行中"→按钮变为"停止采集" | 23 | +| C2.10 | 停止采集按钮 | 点击→状态切换为"已停止"→按钮变为"启动采集" | 23 | +| C2.11 | 刷新配置按钮 | 点击→成功提示 | 23 | +| C2.12 | 表格布局铺满 | 排行表格宽度=100%容器宽度 | 21 | +| C2.13 | 告警列表可点击跳转 | 点击告警→跳转告警中心 | 22 | + +### C3. 设备管理(/machine + /machine/:id) + +| # | 测试点 | 期望结果 | 维度 | +|---|--------|---------|------| +| C3.1 | 机床列表加载 | 表格有数据,每列有值 | 4,5 | +| C3.2 | 车间/品牌/状态下拉筛选 | 选项≥1,选择后筛选生效 | 8,9,10 | +| C3.3 | 关键词搜索 | 输入→查询→结果包含关键词 | 11 | +| C3.4 | 分页 | 切换页码,数据变化 | 14 | +| C3.5 | 新增机床 | 填写表单→提交→列表刷新→新机床出现 | 15,16 | +| C3.6 | 编辑机床 | 修改→保存→列表更新 | 15,16 | +| C3.7 | 删除机床 | 确认→行消失 | 23 | +| C3.8 | 启停机床 | 切换→状态标签变更 | 23 | +| C3.9 | 点击设备名称跳转详情 | 跳转到详情页,URL含id,详情页有数据 | 22 | +| C3.10 | 详情页-实时采集状态 | 状态信息展示 | 2 | +| C3.11 | 详情页-今日产量 | 表格有数据 | 4,5 | +| C3.12 | 详情页-产量趋势 | 图表有渲染 | 3.1 | +| C3.13 | 详情页-采集记录 | 表格有数据 | 4,5 | +| C3.14 | 表格布局铺满 | 表格宽度=100%容器宽度 | 21 | +| C3.15 | 空数据状态 | 不可能的筛选→行数=0+不白屏 | 19 | +| C3.16 | 重置按钮 | 筛选恢复默认 | 13 | + +### C4. 品牌模板(/brand + /brand/create + /brand/:id/edit) + +| # | 测试点 | 期望结果 | 维度 | +|---|--------|---------|------| +| C4.1 | 品牌列表 | 表格有数据 | 4,5 | +| C4.2 | 新增品牌 | 填写→提交→成功 | 15,16 | +| C4.3 | 编辑品牌(含字段映射) | 修改字段映射→保存→刷新后保留 | 15,16 | +| C4.4 | 复制品牌 | 点复制→新品牌出现(名称含"副本") | 23 | +| C4.5 | 删除品牌 | 确认→行消失 | 23 | +| C4.6 | 启停品牌 | 切换→状态变更 | 23 | +| C4.7 | 标准字段列表 | 下拉有选项 | 8 | +| C4.8 | 点击品牌名称跳转编辑 | 跳转到编辑页,字段预填 | 22 | +| C4.9 | 表格布局铺满 | 表格宽度=100%容器宽度 | 21 | + +### C5. 采集地址(/collect-address + /collect-address/:id) + +| # | 测试点 | 期望结果 | 维度 | +|---|--------|---------|------| +| C5.1 | 地址列表 | 表格有数据 | 4,5 | +| C5.2 | 新增地址 | 填写URL、品牌→提交→成功 | 15,16 | +| C5.3 | 编辑地址 | 修改→保存 | 15,16 | +| C5.4 | 删除地址 | 确认→行消失 | 23 | +| C5.5 | 启停地址 | 切换→状态变更 | 23 | +| C5.6 | 点击地址名称跳转详情 | 跳转详情页 | 22 | +| C5.7 | 详情-关联机床列表 | 有数据 | 4 | +| C5.8 | 详情-采集记录 | 有数据 | 4 | +| C5.9 | 详情-原始JSON | JSON展示区有内容 | 2 | +| C5.10 | 表格布局铺满 | 表格宽度=100%容器宽度 | 21 | +| C5.11 | 重置按钮 | 筛选恢复默认 | 13 | + +### C6. 员工管理(/worker + /worker/:id) + +| # | 测试点 | 期望结果 | 维度 | +|---|--------|---------|------| +| C6.1 | 员工列表 | 表格有数据 | 4,5 | +| C6.2 | 新增员工 | 填写→提交→成功 | 15,16 | +| C6.3 | 编辑员工 | 修改→保存 | 15,16 | +| C6.4 | 删除员工 | 确认→行消失 | 23 | +| C6.5 | 启停员工 | 切换→状态变更 | 23 | +| C6.6 | 点击员工名称跳转详情 | 跳转详情页 | 22 | +| C6.7 | 详情-绑定机床 | 列表有数据或可添加 | 4 | +| C6.8 | 详情-今日产量 | 表格有数据 | 4 | +| C6.9 | 详情-产量趋势 | 图表有渲染 | 3.1 | +| C6.10 | 表格布局铺满 | 表格宽度=100%容器宽度 | 21 | +| C6.11 | 重置按钮 | 筛选恢复默认 | 13 | + +### C7. 产量报表(/production) + +| # | 测试点 | 期望结果 | 维度 | +|---|--------|---------|------| +| C7.1 | 日汇总卡片有值 | totalQuantity等≠空 | 3 | +| C7.2 | 日产量列表 | 表格有数据,运行时间/切削时间/日状态有值 | 4,5,6 | +| C7.3 | 车间/机床/工人下拉 | 选项≥1,筛选生效 | 8,9,10 | +| C7.4 | 日期范围筛选 | 切换→数据变化 | 12 | +| C7.5 | 程序名文本筛选 | 输入→匹配 | 11 | +| C7.6 | 重置按钮 | 筛选恢复默认 | 13 | +| C7.7 | 修正弹窗 | 打开→填写→提交→列表刷新→修正标记出现 | 15,16 | +| C7.8 | 修正历史弹窗 | 打开→有历史记录 | 15 | +| C7.9 | 分页 | 切换页码→数据变化 | 14 | +| C7.10 | 导出 | 触发下载 | 23 | +| C7.11 | 汇总卡片 vs API对账 | 调API→对比卡片值一致 | 17 | +| C7.12 | 表格布局铺满 | 表格宽度=100%容器宽度 | 21 | +| C7.13 | 下拉选项值有效性 | 每项文本非空、value可选中 | 18 | + +### C8. 告警中心(/alert) + +| # | 测试点 | 期望结果 | 维度 | +|---|--------|---------|------| +| C8.1 | 告警统计 | 卡片有值(总数/未处理/已处理) | 3 | +| C8.2 | 告警列表 | 表格有数据 | 4,5 | +| C8.3 | 类型/状态筛选 | 选项≥1,筛选生效 | 8,9,10 | +| C8.4 | 处理单条告警 | 点处理→状态变为已处理 | 23 | +| C8.5 | 批量处理 | 勾选→批量处理→状态批量变更 | 23 | +| C8.6 | 日期筛选 | 切换→数据变化 | 12 | +| C8.7 | 表格布局铺满 | 表格宽度=100%容器宽度 | 21 | +| C8.8 | 重置按钮 | 筛选恢复默认 | 13 | + +### C9. 系统设置(/settings) + +| # | 测试点 | 期望结果 | 维度 | +|---|--------|---------|------| +| C9.1 | 配置项列表 | 表格有数据 | 4 | +| C9.2 | 编辑配置项 | 修改→保存→值更新 | 15,16 | +| C9.3 | 重置Token | 点击→确认→新Token生成 | 23 | +| C9.4 | 修改密码 | 填写→提交→成功提示 | 15,16 | +| C9.5 | 车间管理-列表 | 表格有数据 | 4 | +| C9.6 | 车间管理-新增 | 填写→提交→成功 | 15,16 | +| C9.7 | 车间管理-编辑 | 修改→保存 | 15,16 | +| C9.8 | 车间管理-删除 | 确认→行消失 | 23 | +| C9.9 | 车间管理-启停 | 切换→状态变更 | 23 | + +### C10. 操作日志(/log) + +| # | 测试点 | 期望结果 | 维度 | +|---|--------|---------|------| +| C10.1 | 产量修正日志 | 表格有数据 | 4,5 | +| C10.2 | 系统运行日志 | 表格有数据 | 4,5 | +| C10.3 | 日期筛选 | 切换→数据变化 | 12 | +| C10.4 | 导出 | 触发下载 | 23 | +| C10.5 | 表格布局铺满 | 表格宽度=100%容器宽度 | 21 | + +### C11. 大屏配置(/screen-config) + +| # | 测试点 | 期望结果 | 维度 | +|---|--------|---------|------| +| C11.1 | 卡片配置列表 | 表格有数据 | 4 | +| C11.2 | 新增卡片配置 | 填写→提交→成功 | 15,16 | +| C11.3 | 编辑卡片配置 | 修改→保存 | 15,16 | +| C11.4 | 删除卡片配置 | 确认→行消失 | 23 | +| C11.5 | 启停卡片 | 切换→状态变更 | 23 | +| C11.6 | 筛选配置列表 | 表格有数据 | 4 | +| C11.7 | 新增筛选项 | 填写→提交→成功 | 15,16 | +| C11.8 | 编辑筛选项 | 修改→保存 | 15,16 | +| C11.9 | 删除筛选项 | 确认→行消失 | 23 | + +--- + +## 五、测试域D:端到端联动测试 + +> 核心验证:数据从模拟器→采集服务→数据库→管理后台的完整链路。 + +### D1. 完整数据链路验证 + +| # | 测试场景 | 操作步骤 | 期望结果 | 验证方法 | +|---|---------|---------|---------|---------| +| D1.1 | 正常采集全链路 | ①模拟器运行 ②采集服务启动 ③等待2个采集周期 | 模拟器输出→采集服务获取→解析→写DB→管理后台可查 | ①查模拟器admin/api/logs有请求记录 ②查collect_record有新数据 ③管理后台设备列表last_collect_time更新 | +| D1.2 | 机床状态实时反映 | 模拟器设备在线→采集→查管理后台 | 机床is_online=1,last_device_status非空 | 查cnc_machine表 + 管理后台设备列表 | +| D1.3 | NC程序切换→生产段记录 | ①记录当前程序名和partCount ②触发program_change事件 ③等待2个采集周期 | 旧段结账,新段创建,quantity计算正确 | 查cnc_production_segment | +| D1.4 | 产量汇总 | 采集运行≥5分钟(完成若干段)→查仪表盘/产量报表 | 日汇总卡片有值,日产量列表有记录,数量与段记录一致 | 对比cnc_daily_production与cnc_production_segment | + +### D2. 采集服务启停联动 + +| # | 测试场景 | 操作步骤 | 期望结果 | 验证方法 | +|---|---------|---------|---------|---------| +| D2.1 | 管理后台启动采集 | ①仪表盘点"启动采集" ②等待1秒 ③查仪表盘状态 | 状态切换为"运行中",uptime递增 | Playwright + API | +| D2.2 | 停止→数据停止更新 | ①停止采集 ②等待1分钟 ③查collect_record | 停止后无新采集记录 | `SELECT MAX(collect_time) FROM cnc_collect_record` 应早于停止时间 | +| D2.3 | 重启→数据恢复 | ①重新启动采集 ②等待1个采集周期 | 新记录写入,心跳恢复running | 查DB | + +### D3. 模拟器异常联动 + +| # | 测试场景 | 操作步骤 | 期望结果 | 验证方法 | +|---|---------|---------|---------|---------| +| D3.1 | 模拟器挂了→采集失败→告警 | ①停止模拟器 ②等待采集重试3次+告警阈值 | 采集记录is_success=0,告警表新增collect_fail记录 | 查log_collect_raw + cnc_alert | +| D3.2 | 模拟器恢复→采集恢复 | ①重启模拟器 ②等待采集 | is_success=1,fail_count归零 | 查DB | +| D3.3 | 空数据→采集处理 | 模拟器设empty模式 | 采集不崩溃,log记录空响应 | 查日志 | +| D3.4 | 超时→采集超时 | 模拟器设timeout模式 | 采集超时,记录失败 | 查log_collect_raw | + +### D4. 配置变更联动 + +| # | 测试场景 | 操作步骤 | 期望结果 | 验证方法 | +|---|---------|---------|---------|---------| +| D4.1 | 新增采集地址→刷新 | ①管理后台新增采集地址 ②仪表盘点"刷新配置" ③查采集服务status | workerCount+1 | 调5800 status API | +| D4.2 | 禁用地址→刷新 | ①禁用某采集地址 ②刷新 | workerCount-1 | 调status | +| D4.3 | 修改采集间隔 | ①DB修改collect_interval ②等配置轮询(30秒) ③观察采集频率变化 | 采集间隔变更 | 对比两次collect_time差值 | + +### D5. 日终汇总联动 + +| # | 测试场景 | 操作步骤 | 期望结果 | 验证方法 | +|---|---------|---------|---------|---------| +| D5.1 | 手动触发日终汇总 | ①确保有当日生产段数据 ②修改配置的汇总时间为当前时间+1分钟 ③等待触发 | cnc_daily_production有当日记录,total_quantity与段记录quantity之和一致 | 查DB | + +### D6. 数据一致性交叉验证 + +| # | 验证项 | SQL/方法 | 通过标准 | +|---|--------|---------|---------| +| D6.1 | 生产段 vs 采集记录 | `SELECT ps.machine_id, ps.program_name, ps.quantity, COUNT(cr.id) FROM cnc_production_segment ps LEFT JOIN cnc_collect_record cr ON cr.machine_id=ps.machine_id AND cr.collect_time BETWEEN ps.start_time AND IFNULL(ps.end_time, NOW()) GROUP BY ps.id` | 每段至少有1条采集记录 | +| D6.2 | 日产量 vs 生产段 | `SELECT dp.machine_id, dp.production_date, dp.total_quantity, SUM(ps.quantity) FROM cnc_daily_production dp JOIN cnc_production_segment ps ON ps.machine_id=dp.machine_id AND ps.production_date=dp.production_date GROUP BY dp.id` | total_quantity = SUM(quantity) | +| D6.3 | 工人日汇总 vs 日产量 | `SELECT ws.worker_id, ws.total_quantity, SUM(dp.total_quantity) FROM cnc_worker_daily_summary ws JOIN cnc_worker_machine wm ON wm.worker_id=ws.worker_id JOIN cnc_daily_production dp ON dp.machine_id=wm.machine_id AND dp.production_date=ws.production_date GROUP BY ws.id` | 数值一致 | +| D6.4 | 模拟器零件数 vs DB零件数 | 对比模拟器 `/admin/api/full-summary` 的 totalParts 与 DB `cnc_daily_production.total_quantity` | 允许差异(采集周期延迟),但趋势一致 | +| D6.5 | 心跳 uptime 连续性 | `SELECT id, status, uptime_seconds, created_at FROM cnc_log.log_collector_heartbeat WHERE service_id='collector-service' ORDER BY id DESC LIMIT 20` | running记录uptime递增,无跳变 | +| D6.6 | 原始JSON vs 解析后数据 | 取一条log_collect_raw.raw_json,解析后与cnc_collect_record对应记录对比 | 字段值一致 | + +--- + +## 六、测试通过标准 + +| 类别 | 标准 | +|------|------| +| **A 模拟器** | 所有A1-A4测试点通过,管理API全部可操作,异常模式全部可设置和恢复 | +| **B 采集服务** | 所有B1-B6测试点通过,数据写入DB正确,异常不崩溃 | +| **C 管理后台** | 所有C1-C11模块按维度总表(23维度)逐项通过,CRUD操作闭环 | +| **D 联动测试** | D1-D6全部通过,数据链路完整,交叉验证一致 | +| **零容忍** | 无白屏、无500错误、无数据丢失、无空字段(设计允许NULL的除外) | + +--- + +## 七、测试执行顺序 + +``` +1. 启动所有组件(模拟器→采集服务→确认IIS运行) +2. 域A:模拟器独立测试(确认数据源正常) +3. 域B:采集服务独立测试(确认采集流程正确) +4. 域C:管理后台逐页面测试(确认展示正确) +5. 域D:联动测试(按D1→D2→D3→D4→D5→D6顺序) +6. 域D6:数据一致性交叉验证(全链路数据对账) +``` + +--- + +## 八、测试点统计 + +| 测试域 | 测试点数 | +|--------|---------| +| A 模拟器 | 21 | +| B 采集服务 | 22 | +| C 管理后台 | 65 | +| D 联动测试 | 21 | +| **合计** | **129** |