|
|
# 测试规范
|
|
|
|
|
|
**版本:** 2026-05-03
|
|
|
**适用范围:** CNC机床数据采集系统 — 前端管理后台 + 后端API
|
|
|
|
|
|
---
|
|
|
|
|
|
## 一、6条铁律
|
|
|
|
|
|
| # | 铁律 | 要求 |
|
|
|
|---|------|------|
|
|
|
| 1 | **接口先验证** | 改了任何API,立即用PowerShell调用,逐字段确认返回值与前端绑定一致 |
|
|
|
| 2 | **数据断言必须具体** | 禁止只检查 `toBeVisible()`,必须检查文本内容,排除空/`-`/`--`/`undefined`/`null` |
|
|
|
| 3 | **下拉框必须展开验证** | 展开→选项≥1→选择→确认显示值→点查询→确认筛选生效 |
|
|
|
| 4 | **表格必须检查每列** | 行数>0 + 第一行每列文本非空(日期、名称、数值、时间、状态逐列检查) |
|
|
|
| 5 | **卡片数值必须非空** | 每个卡片数值 ≠ 空 ≠ `-` ≠ `--` ≠ `undefined` ≠ `null`,允许为0时须注释说明 |
|
|
|
| 6 | **改完即验证** | 每改一处→编译→API验证→浏览器验证,禁止累积 |
|
|
|
|
|
|
---
|
|
|
|
|
|
## 二、验证层级
|
|
|
|
|
|
| 层级 | 执行时机 | 命令/方法 | 通过标准 |
|
|
|
|------|----------|-----------|----------|
|
|
|
| **L1 编译** | 每次代码改动后 | `dotnet build src\CncWebApi\CncWebApi.csproj` + `cd frontend && npm run build` | 两个命令退出码0 |
|
|
|
| **L2 API** | 改了后端后 | PowerShell调用改动过的API | HTTP 200 + `code=0` + `data`非null + 关键字段非空 |
|
|
|
| **L3 浏览器** | 改了前端后 | `cd frontend && npx playwright test e2e/smoke-iis.spec.ts --project=chromium` | 对照5.0维度总表逐项通过 |
|
|
|
| **L4 发布** | 交付前 | `appcmd recycle apppool "haoliang"` + 重复L2+L3 | 全部通过 + 局域网可访问 |
|
|
|
|
|
|
> 编译通过 ≠ 功能正确。L1只是最基本的大门。
|
|
|
|
|
|
---
|
|
|
|
|
|
## 三、前后端接口契约验证
|
|
|
|
|
|
每次新增或修改API返回字段时必须执行:
|
|
|
|
|
|
| 检查项 | 通过标准 |
|
|
|
|--------|----------|
|
|
|
| DTO字段名 vs API实际返回JSON | 一致(考虑camelCase序列化:`TotalQuantity` → `totalQuantity`) |
|
|
|
| API返回字段名 vs 前端绑定 | 完全一致或兼容(`??` 回退) |
|
|
|
| 返回数据结构 | 前端取值路径正确(`res.data.items` vs `res.data`) |
|
|
|
| 空值处理 | 前端显示占位符(`-` 或 `暂无数据`),不白屏不报错 |
|
|
|
| 分页格式 | 数组 `[{...}]` vs 分页对象 `{items:[], total:0}` 前后端一致 |
|
|
|
| 枚举值 | 前端处理整数和字符串两种情况 |
|
|
|
| DateTime | 前端兼容 `"2026-05-03T00:00:00"` 和 `"2026-05-03"` |
|
|
|
|
|
|
---
|
|
|
|
|
|
## 四、Playwright E2E测试标准
|
|
|
|
|
|
> **强制要求:每次编写Playwright测试,必须逐项对照5.0维度总表。每个维度有测试用例或注释说明跳过原因。**
|
|
|
|
|
|
### 5.0 测试维度总表(每个页面必查)
|
|
|
|
|
|
| # | 维度 | 必须断言 | 适用 | 禁止 |
|
|
|
|---|------|----------|------|------|
|
|
|
| 1 | 页面加载 | URL正确 + 关键元素可见 | 所有页面 | 只goto不等待 |
|
|
|
| 2 | 默认数据 | 打开即有数据(行数>0 / 卡片有值) | 有数据展示的页面 | 不检查数据 |
|
|
|
| 3 | 汇总卡片数值 | ≠ 空 ≠ `-` ≠ `--` ≠ `undefined` ≠ `null` | 有统计卡片的页面 | 只检查可见 |
|
|
|
| 3.1 | 图表有数据 | Canvas/SVG已渲染 + 有数据点/色块(非空白) | 有ECharts/Chart组件的页面 | 只检查容器可见 |
|
|
|
| 4 | 表格行数 | `.el-table__row` > 0 | 有表格的页面 | 只检查table可见 |
|
|
|
| 5 | 表格每列有值 | 第一行逐列文本非空 | 有表格的页面 | 只检查前2-3列 |
|
|
|
| 6 | 时间/数值列 | 有具体数值(非空非NULL) | 有时间/数值列的页面 | 跳过 |
|
|
|
| 7 | 状态标签 | 为已知中文文案(正常/离线/缺失/告警) | 有状态列的页面 | 不检查文本 |
|
|
|
| 8 | 下拉框展开 | 选项≥1 + 每项文本非空非占位 | 有下拉框的页面 | 只检查select可见 |
|
|
|
| 9 | 下拉框选择 | 选中→显示label→查询→筛选生效 | 有下拉框的页面 | 不验证筛选效果 |
|
|
|
| 10 | 筛选生效 | 选条件→查询→表格数据变化 | 有查询功能的页面 | 不验证变化 |
|
|
|
| 11 | 文本筛选 | 输入关键词→查询→结果每行包含关键词 | 有搜索框的页面 | 不验证匹配度 |
|
|
|
| 12 | 日期筛选 | 切换日期→查询→数据变化 | 有日期选择的页面 | 不验证效果 |
|
|
|
| 13 | 重置按钮 | 所有筛选恢复默认占位符 | 有重置按钮的页面 | 不验证清空 |
|
|
|
| 14 | 分页切换 | 第2页高亮 + 表格第一行数据变化 | 数据>1页 | 只检查组件可见 |
|
|
|
| 15 | 弹窗打开 | 可见 + 标题正确 + 表单有初始值 | 有弹窗的页面 | 不验证标题和内容 |
|
|
|
| 16 | 弹窗提交闭环 | 填写→提交→成功提示→列表刷新→数据变更 | 有写操作弹窗 | 只验证能打开 |
|
|
|
| 17 | API vs 页面对账 | 调API拿JSON→对比页面显示值 | 有统计卡片的页面 | 不对比API值 |
|
|
|
| 18 | 下拉选项值有效性 | 每项文本非空、value可选中 | 有下拉框的页面 | 不验证选项内容 |
|
|
|
| 19 | 空数据状态 | 不可能的条件→行数=0 + 不白屏不报错 | 有筛选的页面 | 不验证极端情况 |
|
|
|
| 20 | 错误处理 | 异常场景→友好提示不白屏 | 所有页面 | 不考虑异常 |
|
|
|
|
|
|
### 5.1 页面类型速查
|
|
|
|
|
|
| 页面类型 | 必须覆盖维度 |
|
|
|
|----------|-------------|
|
|
|
| 列表页(表格+筛选) | 1,2,4,5,8,9,10,13,14,19 |
|
|
|
| 列表页(表格+筛选+卡片) | 1,2,3,4,5,6,7,8,9,10,13,14,17,19 |
|
|
|
| 仪表盘/概览页 | 1,2,3,3.1,5,6,9,12,17,20 |
|
|
|
| 详情/表单页 | 1,15,16 |
|
|
|
| 所有页面 | 1,20 |
|
|
|
|
|
|
### 5.2 交互控件矩阵
|
|
|
|
|
|
| 控件 | 验证动作 | 通过标准 |
|
|
|
|------|----------|----------|
|
|
|
| 下拉框 | 展开→选择→查询 | 选项≥1,显示选中label,筛选生效 |
|
|
|
| 日期选择器 | 选择日期 | 输入框显示 `YYYY-MM-DD` |
|
|
|
| 查询按钮 | 点击 | 表格刷新 |
|
|
|
| 重置按钮 | 点击 | 所有筛选恢复默认 |
|
|
|
| 分页 | 切换页码 | 数据变化,页码高亮 |
|
|
|
| 弹窗-打开 | 点击触发 | 可见,标题正确,表单有初始值 |
|
|
|
| 弹窗-提交 | 填写→提交 | 成功提示,列表刷新 |
|
|
|
| 导出 | 点击 | 触发下载或提示 |
|
|
|
|
|
|
### 5.3 数据展示矩阵
|
|
|
|
|
|
| 元素 | 验证标准 |
|
|
|
|------|----------|
|
|
|
| 汇总卡片 | 非空 ∧ ≠ `""` ∧ ≠ `"-"` ∧ ≠ `"--"` ∧ ≠ `"undefined"` ∧ ≠ `"null"` |
|
|
|
| 图表(ECharts等) | Canvas/SVG存在 + 非空白(有数据点/扇形/柱状) |
|
|
|
| 表格数据列 | 第一行每列有文本值 |
|
|
|
| 状态标签 | 已知中文文案 |
|
|
|
| 时间列 | 有值且格式正确 |
|
|
|
| 空状态 | 显示"暂无数据" |
|
|
|
|
|
|
### 5.4 断言示例
|
|
|
|
|
|
```typescript
|
|
|
// 数值断言(排除空/占位符)
|
|
|
const text = await locator.textContent()
|
|
|
expect(text).toBeTruthy()
|
|
|
expect(text!.trim()).not.toBe('')
|
|
|
expect(text!.trim()).not.toBe('-')
|
|
|
expect(text!.trim()).not.toBe('--')
|
|
|
|
|
|
// 下拉框断言(展开+选项)
|
|
|
const options = page.locator('.el-select-dropdown__item')
|
|
|
expect(await options.count()).toBeGreaterThan(0)
|
|
|
|
|
|
// 表格断言(行数+列值)
|
|
|
const rows = page.locator('.el-table__body-wrapper .el-table__row')
|
|
|
expect(await rows.count()).toBeGreaterThan(0)
|
|
|
```
|
|
|
|
|
|
---
|
|
|
|
|
|
## 五、API验证方法
|
|
|
|
|
|
### 登录获取Token
|
|
|
|
|
|
```powershell
|
|
|
$loginRes = Invoke-RestMethod -Uri "http://127.0.0.1/api/admin/login" -Method Post -ContentType "application/json" -Body '{"username":"admin","password":"admin123"}'
|
|
|
$token = $loginRes.data.token
|
|
|
$headers = @{ Authorization = "Bearer $token" }
|
|
|
```
|
|
|
|
|
|
### 必须非空字段
|
|
|
|
|
|
| API端点 | 必须非空字段 |
|
|
|
|----------|-------------|
|
|
|
| `/admin/production/daily-summary` | `totalQuantity`, `activeMachineCount`, `totalCuttingTime`, `avgQuantityPerMachine` |
|
|
|
| `/admin/production/daily` | `items[].machineName`, `items[].totalQuantity`, `items[].date` |
|
|
|
| `/admin/workshop/list` | `items[].value`, `items[].label` |
|
|
|
| `/admin/machine/list` | `items[].value`, `items[].label` |
|
|
|
| `/admin/worker/list` | `items[].value`, `items[].label` |
|
|
|
| `/admin/dashboard/statistics` | 各统计卡片字段 |
|
|
|
| `/admin/collector/status` | `status` |
|
|
|
|
|
|
---
|
|
|
|
|
|
## 六、发布前Checklist
|
|
|
|
|
|
- [ ] `dotnet build src\CncWebApi\CncWebApi.csproj` → 0错误
|
|
|
- [ ] `cd frontend && npm run build` → 0错误
|
|
|
- [ ] 前端build输出已复制到 `src\CncWebApi\admin\`
|
|
|
- [ ] 回收AppPool:`appcmd recycle apppool "haoliang"`
|
|
|
- [ ] 改动过的API端点用PowerShell调用,返回值正确
|
|
|
- [ ] Playwright冒烟测试通过:`cd frontend && npx playwright test e2e/smoke-iis.spec.ts --project=chromium`
|
|
|
- [ ] `git add` + `git commit -m "中文描述"` + `git push`
|
|
|
|
|
|
---
|
|
|
|
|
|
## 七、反模式清单
|
|
|
|
|
|
| # | 禁止 | 必须改为 |
|
|
|
|---|------|----------|
|
|
|
| 1 | 编译通过 = 测试通过 | 验证功能 |
|
|
|
| 2 | 只检查 `toBeVisible()` | 检查文本值,排除空/占位符 |
|
|
|
| 3 | SQL写 `NULL AS 字段名` 占位 | 实现或抛异常 |
|
|
|
| 4 | DTO加字段不填充值 | 追踪到Service层实现填充 |
|
|
|
| 5 | 改完代码不发布到IIS | 每次改动发布后验证 |
|
|
|
| 6 | Playwright不操作控件 | 模拟用户操作:点击、选择、输入 |
|
|
|
| 7 | 累积改动后批量验证 | 改完一处立即验证 |
|
|
|
| 8 | 前端凭假设绑定字段名 | 对照API实际返回值 |
|
|
|
| 9 | 硬编码配置值 | 从配置文件读取 |
|
|
|
| 10 | 不检查组件库格式要求 | 查阅文档(如 dayjs `YYYY-MM-DD`) |
|
|
|
| 11 | 测试不按维度表逐项覆盖 | 对照5.0维度总表 |
|
|
|
| 12 | 测试只覆盖部分页面 | 每个改动涉及的页面都要覆盖 |
|
|
|
| 13 | 新增维度后不更新维度总表 | 新发现的问题必须补充为新维度 |
|
|
|
| 14 | 图表只检查容器DOM存在 | 验证Canvas/SVG有实际渲染内容(数据点/色块) |
|