规范:新增10条联调测试规范——后端5条(端点对照表/DTO断言/布尔类型/需求驱动测试/覆盖率声明)+前端4条(Mock切换Checklist/RESTful调用/分页组件/布尔类型)+联调测试1条(逐字段验证)

main
haoliang 1 week ago
parent b5bff2a815
commit 7052cbf5a1

@ -371,6 +371,137 @@ mock/*.ts 文件内容来源:
- 大屏看板:独立深色主题(#0f0f1a背景/#1a1a2e卡片),样式文件 `styles/screen.scss` - 大屏看板:独立深色主题(#0f0f1a背景/#1a1a2e卡片),样式文件 `styles/screen.scss`
- 不引入Tailwind CSS - 不引入Tailwind CSS
### Mock→API切换 Checklist强制
联调切换时,开发者必须执行以下检查清单,逐项确认后才能声明切换完成:
1. **全局搜索残留**
- 搜索代码中所有 `mock-api` 字符串,确认零残留
- 搜索所有 `/mock-api/` URL 引用,确认零残留
2. **逐调用点确认URL**
- 搜索所有 `request.get(`、`request.post(`、`request.put(`、`request.delete(` 调用点
- 输出完整清单(文件路径 + 行号 + URL
- 逐个确认每个 URL 已从 Mock 风格切换为 RESTful 风格
3. **逐调用点确认HTTP方法**
- 写操作(新增/编辑/删除/启停)必须使用正确的 RESTful 方法POST/PUT/DELETE
- 禁止写操作用 GET
- 禁止所有操作都用 POSTMock 遗留)
4. **对照API设计文档**
- 打开 `docs/03-API接口设计.md` 的正式API列
- 逐个端点确认前端调用 URL 和 Method 与文档一致
**检查模板:**
```
模块:设备管理
切换日期2026-04-XX
| # | 前端方法 | 文件 | Mock URL | 正式 URL | HTTP Method | 已确认 |
|---|---------|------|---------|---------|-------------|--------|
| 1 | loadData | MachineListPage.vue | POST /mock-api/machine/list | GET /api/admin/machine | GET | ✅ |
| 2 | handleCreate | MachineListPage.vue | POST /mock-api/machine/create | POST /api/admin/machine | POST | ✅ |
| 3 | handleEdit | MachineListPage.vue | POST /mock-api/machine/update | PUT /api/admin/machine/{id} | PUT | ✅ |
| ... | ... | ... | ... | ... | ... | ... |
```
### RESTful 调用规范
1. **资源 ID 必须使用路径参数传递**
```typescript
// ✅ 正确ID 在 URL 路径中
request.get(`/api/admin/machine/${id}/status`)
request.put(`/api/admin/machine/${id}/toggle`)
// ❌ 错误ID 在 query 参数中
request.get('/api/admin/machine/status', { params: { id } })
```
2. **禁止自行编造后端不存在的接口**
- 前端调用的每个 URL 必须在 `docs/03-API接口设计.md` 的正式API列中存在
- 批量操作如果后端只提供单个操作接口,前端通过循环调用实现,不编造批量端点
3. **代码审查必检项**
- 每个新增的 `request.xxx()` 调用,审查时必须对照 API 设计文档确认 URL 和 Method 正确
### el-pagination 使用规范
使用 `<el-pagination>` 组件时,**必须同时**绑定以下事件:
```vue
<!-- ✅ 正确v-model + 事件绑定 -->
<el-pagination
v-model:current-page="query.page"
v-model:page-size="query.pageSize"
:page-sizes="[20, 50, 100]"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
@current-change="loadData"
@size-change="handleSizeChange"
/>
<script setup>
const handleSizeChange = () => {
query.page = 1 // 切换每页条数时回到第1页
loadData()
}
</script>
```
```vue
<!-- ❌ 错误:只有 v-model没有事件绑定 -->
<!-- v-model 只更新响应式变量的值,不会自动触发数据加载 -->
<el-pagination
v-model:current-page="query.page"
v-model:page-size="query.pageSize"
:total="total"
/>
```
**原因**`v-model:current-page` 只是双向绑定数据,页码变化时不会自动调用 `loadData()`。必须通过 `@current-change``@size-change` 事件手动触发数据请求。
### 布尔字段类型规范
1. **TypeScript 接口中二元状态字段使用 `boolean` 类型**
```typescript
// ✅ 正确
interface Machine {
isOnline: boolean
isEnabled: boolean
}
// ❌ 错误
interface Machine {
isOnline: number // 0/1 语义不明确
isEnabled: number // 隐式转换碰巧正确但不可靠
}
```
2. **后端返回 `int` 时的前端处理**:如果后端 DTO 暂时无法改为 `bool`(需协调),前端应在 API 响应拦截或数据转换层统一转为 `boolean`
```typescript
// 在 loadData 或 API 响应处理中
const machine = {
...raw,
isOnline: Boolean(raw.isOnline),
isEnabled: Boolean(raw.isEnabled),
}
```
3. **禁止在模板中使用 number 做隐式布尔判断**
```vue
<!-- ❌ 错误number 隐式转换 -->
<el-tag :type="detail.isOnline ? 'success' : 'info'">
<!-- ✅ 正确boolean 显式判断 -->
<el-tag :type="detail.isOnline ? 'success' : 'info'">
```
### 大屏独立规范 ### 大屏独立规范
- 独立Layout`ScreenLayout.vue`(全屏,无侧边栏/面包屑) - 独立Layout`ScreenLayout.vue`(全屏,无侧边栏/面包屑)

@ -92,3 +92,33 @@ AI助手执行任何界面变更前只需读以下文件
- 禁止修改全局规范而不检查模块兼容性 - 禁止修改全局规范而不检查模块兼容性
- 禁止在页面文件中重复全局规范已有内容 - 禁止在页面文件中重复全局规范已有内容
- 禁止使用旧样式 `+---+` 画界面布局 - 禁止使用旧样式 `+---+` 画界面布局
---
## 六、逐字段验证测试规范(联调测试必读)
联调测试时,以下三种场景必须执行逐字段验证,不能只验证"操作成功"
### 1. 编辑测试(逐字段验证)
对每个可编辑字段:
1. 记录原始值 → 修改为新值 → 保存
2. 列表页验证:该字段对应的列显示新值
3. 重新打开编辑弹窗:逐字段比对回填值是否为新值
4. (推荐)通过 API 直接查询数据库,确认数据库中存储的值正确
### 2. 分页测试(数据变化验证)
1. 记录当前页第一条数据的关键字段(如 device_code
2. 切换到第2页
3. 确认第一条数据的关键字段确实变了(不是同一批数据)
4. 切换回第1页
5. 确认数据恢复为之前记录的值
### 3. 详情页测试(逐字段显示验证)
对详情页每个展示字段:
1. 打开已知数据的详情页
2. 逐字段检查:名称、编码、**关联名称**车间名称、品牌名称、工人名称等、IP、状态
3. 空白/异常值不能跳过——如果某个字段显示为空,必须记录为 Bug
4. 特别关注外键关联的名称字段ID 存在但 Name 为空 = Bug

@ -657,6 +657,115 @@ public class MachineRepositoryTests : IDisposable
| 删除测试来"通过"构建 | 禁止,必须修复 | | 删除测试来"通过"构建 | 禁止,必须修复 |
| 忽略 `[Fact(Skip="...")]` | 禁止跳过测试 | | 忽略 `[Fact(Skip="...")]` | 禁止跳过测试 |
### 6.11 API端点实现对照表强制
**适用时机**:每个模块的 Controller + Service 开发完成后、声明"模块完成"之前。
**规范要求:**
1. 打开 `docs/03-API接口设计.md`,复制该模块的完整端点清单
2. 在 `tests/CncService.Tests/Checklists/` 目录下创建对照清单文件,命名规则:`{模块名}-endpoints.md`,每行包含:
```
| 端点 | HTTP方法 | URL | Controller方法 | Service方法 | 测试方法 | 状态 |
|------|---------|-----|---------------|------------|---------|------|
| 机床列表 | GET | /api/admin/machine | GetList | GetList | GetList_xxx | ✅ |
| 机床详情 | GET | /api/admin/machine/{id} | GetById | GetById | GetById_xxx | ✅ |
| 机床状态 | GET | /api/admin/machine/{id}/status | GetStatus | GetStatus | GetStatus_xxx | ❌未实现 |
| ... | ... | ... | ... | ... | ... | ... |
```
3. **全部端点状态为 ✅ 时,才算模块开发完成**
4. 对照清单文件随测试文件一起提交到 Git
**禁止行为:**
- 禁止只实现 CRUD 五件套(列表/详情/新增/编辑/删除)就声称模块完成,忽略设计文档中定义的子端点(如 status、production/today、production/trend、collect-records 等)
- 禁止"测了多少就覆盖多少"——覆盖率数字只统计已存在的方法
### 6.12 DTO断言完整性强制
**规范要求:**
1. GetById、GetDetail 等详情接口的测试,必须对 DTO 中的**每个字段**做断言
2. 外键 ID 字段(如 `WorkshopId`)和关联名称字段(如 `WorkshopName`**必须成对断言**
```csharp
// ✅ 正确ID 和 Name 成对断言
Assert.True(result.WorkshopId > 0);
Assert.NotNull(result.WorkshopName);
Assert.NotEmpty(result.WorkshopName);
// ❌ 错误:只断言 IDName 为 null 也通过
Assert.Equal(1, result.WorkshopId);
// WorkshopName 未断言 → null 也通过测试
```
3. Controller 层测试同样必须对返回对象的每个字段做断言,不能只验证单个字段
**检查方法:**
- 写完测试后,数一下断言语句的数量,必须 ≥ DTO 的 public 属性数量
- 如果 DTO 新增了字段,对应测试必须同步新增断言
### 6.13 布尔字段类型规范
**规范要求:**
1. **C# DTO 层**:二元状态字段使用 `bool` 类型,不用 `int`
```csharp
// ✅ 正确
public bool IsEnabled { get; set; }
public bool IsOnline { get; set; }
// ❌ 错误
public int IsEnabled { get; set; } // 0/1 语义不明确
```
2. **C# Entity 层**:如果 Dapper 映射需要Entity 可以用 `int`/`sbyte`,但必须在 Repository 映射时转为 `bool`
3. **测试断言**:布尔字段用 `Assert.True()`/`Assert.False()`,不用 `Assert.Equal(1, ...)`/`Assert.Equal(0, ...)`
```csharp
// ✅ 正确
Assert.True(result.IsEnabled);
// ❌ 错误——与实现同源,如果实现用错了 int测试也用 int两者同错
Assert.Equal(1, result.IsEnabled);
```
### 6.14 测试从需求文档编写(强制)
**规范要求:**
1. **写测试的输入顺序**
- 第一步:打开 `docs/03-API接口设计.md`,列出该模块所有端点和业务规则
- 第二步:根据端点清单和业务规则编写测试方法签名和断言
- 第三步:运行测试,确认哪些通过、哪些失败(此时再检查实现是否遗漏)
2. **禁止的行为**
- 禁止看 Service/Controller 代码后补测试——这会导致"实现有什么就测什么",遗漏的功能永远不会被发现
- 禁止只测试已存在的方法——API 设计文档中定义但未实现的方法,必须有对应的失败测试(标记为 TODO 或 `[Fact(Skip="端点未实现")]`
3. **新增端点时**:先更新 API 设计文档再写测试TDD 风格),最后写实现
### 6.15 覆盖率诚实声明
**规范要求:**
1. 声明覆盖率时,必须附加以下免责说明:
```
覆盖率统计范围:仅覆盖已实现的 Controller/Service/Repository 方法。
API 设计文档中定义但尚未实现的端点不在统计范围内。
完整性请参照 API 端点实现对照表(见 6.11)。
```
2. **禁止**只报一个数字(如"390个测试100%方法覆盖")而不说明统计范围
3. 每个模块完成时,覆盖率报告必须与端点对照表一起呈现,两个指标缺一不可:
- 已实现方法的覆盖率(方法覆盖 + 分支覆盖)
- 已设计端点的实现率(已实现端点数 / 文档定义端点总数)
--- ---
## 七、依赖注入 ## 七、依赖注入

Loading…
Cancel
Save