You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
测试规范
版本: 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 |
错误处理 |
异常场景→友好提示不白屏 |
所有页面 |
不考虑异常 |
| 21 |
表格布局铺满 |
表格宽度=100%容器宽度,无大片右侧空白 |
有表格的页面 |
只检查表格可见 |
| 22 |
可点击链接跳转 |
表格/卡片中可点击字段→点击→URL跳转正确→目标页面加载成功+有数据 |
有链接/可点击字段的页面 |
不点击链接 |
5.1 页面类型速查
| 页面类型 |
必须覆盖维度 |
| 列表页(表格+筛选) |
1,2,4,5,8,9,10,13,14,19,21,22 |
| 列表页(表格+筛选+卡片) |
1,2,3,4,5,6,7,8,9,10,13,14,17,19,21,22 |
| 仪表盘/概览页 |
1,2,3,3.1,5,6,9,12,17,20,21,22 |
| 详情/表单页 |
1,15,16 |
| 所有页面 |
1,20 |
5.2 交互控件矩阵
| 控件 |
验证动作 |
通过标准 |
| 下拉框 |
展开→选择→查询 |
选项≥1,显示选中label,筛选生效 |
| 日期选择器 |
选择日期 |
输入框显示 YYYY-MM-DD |
| 查询按钮 |
点击 |
表格刷新 |
| 重置按钮 |
点击 |
所有筛选恢复默认 |
| 分页 |
切换页码 |
数据变化,页码高亮 |
| 弹窗-打开 |
点击触发 |
可见,标题正确,表单有初始值 |
| 弹窗-提交 |
填写→提交 |
成功提示,列表刷新 |
| 导出 |
点击 |
触发下载或提示 |
| 可点击链接 |
点击字段→等待跳转→验证URL+目标页数据 |
URL正确,目标页面加载成功且有数据 |
5.3 数据展示矩阵
| 元素 |
验证标准 |
| 汇总卡片 |
非空 ∧ ≠ "" ∧ ≠ "-" ∧ ≠ "--" ∧ ≠ "undefined" ∧ ≠ "null" |
| 图表(ECharts等) |
Canvas/SVG存在 + 非空白(有数据点/扇形/柱状) |
| 表格数据列 |
第一行每列有文本值 |
| 表格布局 |
表格撑满容器宽度,无大片右侧空白;至少一列不设固定width |
| 可点击字段 |
有点击样式(链接色/手型光标)的字段必须点击验证跳转:URL正确+目标页有数据 |
| 状态标签 |
已知中文文案 |
| 时间列 |
有值且格式正确 |
| 空状态 |
显示"暂无数据" |
5.4 断言示例
// 数值断言(排除空/占位符)
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
$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
七、反模式清单
| # |
禁止 |
必须改为 |
| 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有实际渲染内容(数据点/色块) |
| 15 |
表格所有列设固定width导致右侧空白 |
至少一列不设width让其自动填充剩余空间 |
| 16 |
不点击表格中的可跳转链接 |
必须点击链接→验证跳转URL+目标页面有数据 |