# 空间节点管理测试用例文档

> 文档版本：v1.0
> 创建日期：2026-02-16
> 适用范围：空间节点管理模块（MDM服务）

---

## 一、集成测试用例（API 层面）

### 1.1 基础 CRUD 测试

| 用例编号 | 用例名称 | 接口 | 请求参数 | 预期结果 |
|----------|----------|------|----------|----------|
| IT-001 | 创建楼栋 | POST /api/v1/mdm/space-nodes | `{name: "1号楼", nodeType: "BUILDING", projectId: "xxx"}` | 返回 200，treePath 正确，nodeCode 自动生成 |
| IT-002 | 创建单元 | POST /api/v1/mdm/space-nodes | `{name: "1单元", nodeType: "UNIT", parentId: "楼栋ID"}` | parentId 关联正确，treePath 包含父节点 |
| IT-003 | 创建房间 | POST /api/v1/mdm/space-nodes | `{name: "101", nodeType: "ROOM", parentId: "单元ID"}` | 层级关系正确，treePath 完整 |
| IT-004 | 查询树形结构 | GET /api/v1/mdm/space-nodes/tree | `projectId=xxx` | 返回完整树形结构，包含所有层级 |
| IT-005 | 删除节点（无子节点） | DELETE /api/v1/mdm/space-nodes/{id} | 叶子节点ID | 返回 200，节点删除成功 |
| IT-006 | 删除节点（有子节点） | DELETE /api/v1/mdm/space-nodes/{id} | 有子节点的ID | 返回 400，提示"存在子节点，无法删除" |
| IT-007 | 更新节点信息 | PUT /api/v1/mdm/space-nodes/{id} | `{name: "新名称"}` | 返回 200，信息更新成功 |
| IT-008 | 查询节点详情 | GET /api/v1/mdm/space-nodes/{id} | 节点ID | 返回完整节点信息，包含父节点名称 |

### 1.2 批量操作测试

| 用例编号 | 用例名称 | 接口 | 请求参数 | 预期结果 |
|----------|----------|------|----------|----------|
| IT-010 | 批量创建楼栋 | POST /api/v1/mdm/space-nodes/batch | 17个楼栋数据 | 17个楼栋全部创建成功，返回创建列表 |
| IT-011 | 批量创建房间 | POST /api/v1/mdm/space-nodes/batch | 24层 x 4户 = 96个房间数据 | 96个房间批量创建成功，treePath 正确 |
| IT-012 | 自动编码-楼栋 | POST /api/v1/mdm/space-nodes/generate-code | `{nodeType: "BUILDING", projectId: "xxx"}` | 返回 `B001`, `B002` 等编码 |
| IT-013 | 自动编码-单元 | POST /api/v1/mdm/space-nodes/generate-code | `{nodeType: "UNIT", parentId: "楼栋ID"}` | 返回 `U1`, `U2` 等编码 |
| IT-014 | 自动编码-房间 | POST /api/v1/mdm/space-nodes/generate-code | `{nodeType: "ROOM", parentId: "单元ID", floor: 1}` | 返回 `101`, `102` 等编码 |
| IT-015 | 批量删除 | DELETE /api/v1/mdm/space-nodes/batch | 多个叶子节点ID列表 | 全部删除成功 |

### 1.2.1 编码规则配置测试

| 用例编号 | 用例名称 | 接口 | 请求参数 | 预期结果 |
|----------|----------|------|----------|----------|
| IT-016 | 获取编码规则配置 | GET /api/v1/mdm/space-nodes/code-rules | `projectId=xxx` | 返回所有节点类型的编码规则配置 |
| IT-017 | 更新编码规则配置 | PUT /api/v1/mdm/space-nodes/code-rules | `{nodeType: "BUILDING", prefix: "A", sequenceDigits: 3}` | 返回 200，配置更新成功 |
| IT-018 | 自定义前缀编码 | POST /api/v1/mdm/space-nodes/batch | `{prefix: "A8", sequenceDigits: 3, count: 5}` | 生成 A8001, A8002, A8003... |
| IT-019 | 编码预览 | POST /api/v1/mdm/space-nodes/code-preview | `{prefix: "B", sequenceDigits: 2, count: 5}` | 返回 B01, B02, B03, B04, B05 |

### 1.3 项目统计测试

| 用例编号 | 用例名称 | 接口 | 预期结果 |
|----------|----------|------|----------|
| IT-020 | 楼栋数统计 | GET /api/v1/mdm/space-nodes/stats | `COUNT(node_type='BUILDING')` 与实际数量一致 |
| IT-021 | 户数统计 | GET /api/v1/mdm/space-nodes/stats | `COUNT(node_type='ROOM')` 与实际数量一致 |
| IT-022 | 车位数统计 | GET /api/v1/mdm/space-nodes/stats | `COUNT(node_type='PARKING_SPACE')` 与实际数量一致 |
| IT-023 | 按项目统计 | GET /api/v1/mdm/space-nodes/stats?projectId=xxx | 返回指定项目的统计数据 |
| IT-024 | 按类型统计 | GET /api/v1/mdm/space-nodes/stats?nodeType=BUILDING | 返回指定类型的数量 |

### 1.4 异常处理测试

| 用例编号 | 用例名称 | 接口 | 异常场景 | 预期结果 |
|----------|----------|------|----------|----------|
| IT-030 | 创建节点-无效类型 | POST /api/v1/mdm/space-nodes | `nodeType: "INVALID"` | 返回 400，参数校验失败 |
| IT-031 | 创建节点-缺少必填项 | POST /api/v1/mdm/space-nodes | 缺少 `name` 或 `nodeType` | 返回 400，提示必填项缺失 |
| IT-032 | 创建节点-父节点不存在 | POST /api/v1/mdm/space-nodes | `parentId: "不存在的ID"` | 返回 400，父节点不存在 |
| IT-033 | 创建节点-层级不匹配 | POST /api/v1/mdm/space-nodes | ROOM 的父节点是 BUILDING（跳过 UNIT） | 返回 400，层级关系错误 |
| IT-034 | 查询节点-不存在 | GET /api/v1/mdm/space-nodes/{id} | 不存在的ID | 返回 404，节点不存在 |
| IT-035 | 重复节点名称 | POST /api/v1/mdm/space-nodes | 同一父节点下相同名称 | 返回 400，名称重复 |

### 1.5 权限控制测试

| 用例编号 | 用例名称 | 接口 | 权限场景 | 预期结果 |
|----------|----------|------|----------|----------|
| IT-040 | 无权限创建 | POST /api/v1/mdm/space-nodes | 无 `mdm:space:create` 权限 | 返回 403，权限不足 |
| IT-041 | 无权限删除 | DELETE /api/v1/mdm/space-nodes/{id} | 无 `mdm:space:delete` 权限 | 返回 403，权限不足 |
| IT-042 | 跨项目访问 | GET /api/v1/mdm/space-nodes/{id} | 访问其他项目的节点 | 返回 403，无权访问 |
| IT-043 | 只读用户查询 | GET /api/v1/mdm/space-nodes/tree | 仅有查看权限 | 返回 200，可正常查询 |

---

## 二、E2E 测试用例（用户操作层面）

### 2.1 页面导航测试

| 用例编号 | 用例名称 | 前置条件 | 操作步骤 | 预期结果 |
|----------|----------|----------|----------|----------|
| E2E-001 | 进入空间管理 | 已登录管理员账号 | 项目详情页 -> 点击"空间管理"标签 | 显示空间管理页面，包含树形导航和详情面板 |
| E2E-002 | 树形导航展开 | 空间管理页面 | 点击楼栋节点展开图标 | 展开显示该楼栋下的所有单元 |
| E2E-003 | 树形导航收起 | 已展开的树节点 | 点击收起图标 | 子节点收起隐藏 |
| E2E-004 | 节点搜索 | 空间管理页面 | 在搜索框输入"1号楼" | 树形结构高亮显示匹配节点 |
| E2E-005 | 节点定位 | 搜索结果列表 | 点击搜索结果项 | 树形结构自动展开并定位到该节点 |

### 2.2 空间管理操作测试

| 用例编号 | 用例名称 | 前置条件 | 操作步骤 | 预期结果 |
|----------|----------|----------|----------|----------|
| E2E-010 | 创建楼栋 | 空间管理页面 | 1. 点击"新增楼栋"按钮<br>2. 填写楼栋名称"测试楼栋A"<br>3. 点击"保存" | 楼栋创建成功，树形结构自动刷新显示新楼栋 |
| E2E-011 | 创建单元 | 已有楼栋 | 1. 选择楼栋节点<br>2. 点击"新增单元"<br>3. 填写单元名称"1单元"<br>4. 点击"保存" | 单元创建成功，显示在楼栋下 |
| E2E-012 | 创建房间 | 已有单元 | 1. 选择单元节点<br>2. 点击"新增房间"<br>3. 填写房间信息<br>4. 点击"保存" | 房间创建成功 |
| E2E-013 | 批量生成房间 | 已有楼栋 | 1. 选择楼栋节点<br>2. 点击"批量生成"<br>3. 输入楼层数24、每层户数4<br>4. 点击"确认" | 96个房间批量创建成功，显示成功提示 |
| E2E-014 | 编辑节点 | 已有节点 | 1. 选择节点<br>2. 点击"编辑"<br>3. 修改名称<br>4. 点击"保存" | 节点信息更新成功 |
| E2E-015 | 删除节点 | 叶子节点 | 1. 选择叶子节点<br>2. 点击"删除"<br>3. 确认删除 | 节点删除成功，树形结构更新 |
| E2E-016 | 删除有子节点的节点 | 有子节点的节点 | 1. 选择有子节点的节点<br>2. 点击"删除" | 提示"存在子节点，无法删除" |

### 2.3 批量导入测试

| 用例编号 | 用例名称 | 前置条件 | 操作步骤 | 预期结果 |
|----------|----------|----------|----------|----------|
| E2E-020 | 下载楼栋模板 | 空间管理页面 | 1. 点击"导入"按钮<br>2. 选择"楼栋模板"<br>3. 点击"下载模板" | Excel 文件下载成功，包含正确模板格式 |
| E2E-021 | 导入楼栋 | 已下载模板 | 1. 填写楼栋数据<br>2. 上传 Excel 文件<br>3. 点击"确认导入" | 显示导入结果，成功数量和失败原因 |
| E2E-022 | 下载房间模板 | 空间管理页面 | 1. 点击"导入"按钮<br>2. 选择"房间模板"<br>3. 点击"下载模板" | Excel 文件下载成功 |
| E2E-023 | 导入房间 | 已下载模板 | 1. 填写房间数据<br>2. 上传 Excel 文件<br>3. 点击"确认导入" | 显示导入结果 |
| E2E-024 | 导入错误数据 | 错误格式的Excel | 上传格式错误的文件 | 显示错误提示，不执行导入 |
| E2E-025 | 导入部分失败 | 部分数据有误 | 上传包含错误数据的文件 | 显示成功和失败明细，失败记录说明原因 |

### 2.4 数据展示测试

| 用例编号 | 用例名称 | 前置条件 | 操作步骤 | 预期结果 |
|----------|----------|----------|----------|----------|
| E2E-030 | 查看节点详情 | 空间管理页面 | 点击任意节点 | 右侧面板显示节点详细信息 |
| E2E-031 | 查看统计数据 | 空间管理页面 | 查看页面顶部统计区域 | 显示楼栋数、户数、车位数等统计 |
| E2E-032 | 分页展示 | 节点列表超过20条 | 查看列表底部 | 显示分页控件，可翻页 |
| E2E-033 | 排序功能 | 节点列表 | 点击列标题排序 | 列表按指定字段排序 |
| E2E-034 | 筛选功能 | 节点列表 | 选择筛选条件 | 列表按条件过滤显示 |

### 2.5 异常场景测试

| 用例编号 | 用例名称 | 前置条件 | 操作步骤 | 预期结果 |
|----------|----------|----------|----------|----------|
| E2E-040 | 网络中断保存 | 编辑节点时 | 断开网络后点击保存 | 显示网络错误提示，数据不丢失 |
| E2E-041 | 重复提交 | 创建节点时 | 快速连续点击保存按钮 | 只创建一个节点，防止重复提交 |
| E2E-042 | 会话超时 | 长时间未操作 | 会话过期后操作 | 跳转登录页面，提示会话已过期 |
| E2E-043 | 并发编辑 | 两人同时编辑 | 两个用户同时编辑同一节点 | 后保存者提示数据已被修改 |

---

## 三、测试数据

### 3.1 标准测试项目

```json
{
  "project": {
    "id": "test-project-001",
    "name": "测试小区",
    "buildings": 17,
    "floorsPerBuilding": 24,
    "roomsPerFloor": 4,
    "parkingSpaces": 100
  },
  "expected": {
    "totalBuildings": 17,
    "totalUnits": 34,
    "totalRooms": 1632,
    "totalParkingSpaces": 100
  }
}
```

### 3.2 楼栋测试数据

```json
{
  "buildings": [
    { "name": "1号楼", "nodeType": "BUILDING", "nodeCode": "B001" },
    { "name": "2号楼", "nodeType": "BUILDING", "nodeCode": "B002" },
    { "name": "3号楼", "nodeType": "BUILDING", "nodeCode": "B003" }
  ]
}
```

### 3.3 单元测试数据

```json
{
  "units": [
    { "name": "1单元", "nodeType": "UNIT", "nodeCode": "U1", "parentCode": "B001" },
    { "name": "2单元", "nodeType": "UNIT", "nodeCode": "U2", "parentCode": "B001" }
  ]
}
```

### 3.4 房间测试数据

```json
{
  "rooms": [
    { "name": "101", "nodeType": "ROOM", "nodeCode": "101", "floor": 1, "parentCode": "U1" },
    { "name": "102", "nodeType": "ROOM", "nodeCode": "102", "floor": 1, "parentCode": "U1" },
    { "name": "201", "nodeType": "ROOM", "nodeCode": "201", "floor": 2, "parentCode": "U1" },
    { "name": "2401", "nodeType": "ROOM", "nodeCode": "2401", "floor": 24, "parentCode": "U1" }
  ]
}
```

### 3.5 车位测试数据

```json
{
  "parkingSpaces": [
    { "name": "A-001", "nodeType": "PARKING_SPACE", "nodeCode": "P001" },
    { "name": "A-002", "nodeType": "PARKING_SPACE", "nodeCode": "P002" }
  ]
}
```

---

## 四、测试执行说明

### 4.1 集成测试执行

```bash
# 执行所有空间节点集成测试
cd ether-mdm
./mvnw test -Dtest=SpaceNodeIntegrationTest

# 执行特定测试用例
./mvnw test -Dtest=SpaceNodeIntegrationTest#testCreateBuilding
```

### 4.2 E2E 测试执行

```bash
# 启动所有服务
./scripts/start-all-services.sh

# 执行 E2E 测试
cd e2e-tests
npx playwright test space-node.spec.ts
```

### 4.3 测试数据准备

```sql
-- 执行测试数据初始化
psql -U postgres -d ether_mdm -f docs/08-DATABASE/test-data-mdm.sql
```

---

## 五、测试报告模板

### 5.1 测试执行摘要

| 测试类型 | 用例总数 | 通过数 | 失败数 | 通过率 |
|----------|----------|--------|--------|--------|
| 集成测试 | 25 | - | - | - |
| E2E 测试 | 30 | - | - | - |
| **合计** | **55** | - | - | - |

### 5.2 缺陷统计

| 缺陷等级 | 数量 | 已修复 | 待修复 |
|----------|------|--------|--------|
| 严重 | - | - | - |
| 高 | - | - | - |
| 中 | - | - | - |
| 低 | - | - | - |

---

## 六、附录

### 6.1 节点类型枚举

| 类型 | 编码 | 说明 |
|------|------|------|
| 项目 | PROJECT | 根节点 |
| 楼栋 | BUILDING | 楼栋节点 |
| 单元 | UNIT | 单元节点 |
| 楼层 | FLOOR | 楼层节点（可选） |
| 房间 | ROOM | 房间节点 |
| 车位 | PARKING_SPACE | 车位节点 |
| 公共区域 | PUBLIC_AREA | 公共区域节点 |

### 6.2 层级关系约束

```
PROJECT -> BUILDING -> UNIT -> ROOM
PROJECT -> BUILDING -> FLOOR -> ROOM
PROJECT -> PARKING_SPACE
PROJECT -> PUBLIC_AREA
```

### 6.3 编码规则

| 节点类型 | 编码前缀 | 示例 |
|----------|----------|------|
| 楼栋 | B | B001, B002 |
| 单元 | U | U1, U2 |
| 房间 | 楼层+序号 | 101, 2401 |
| 车位 | P | P001, P002 |
