# 业务逻辑正确性测试方案

## 概述

本文档定义用户管理系统核心业务逻辑的正确性测试方案，涵盖用户生命周期管理、设备信任、登录日志、统计数据的端到端正确性验证。

---

## 1. 用户注册与审批流程测试

### 1.1 用户注册创建

**测试目标**：验证用户注册后状态流转与数据一致性的正确性

| 用例编号 | 用例描述 | 前置条件 | 测试步骤 | 预期结果 | 数据库验证 |
|---------|---------|---------|---------|---------|-----------|
| REG-001 | 管理员创建用户并设置初始状态为已激活 | 管理员已登录 | 1. 管理员创建用户，status=1（已激活）<br>2. 提交表单 | 1. API 返回 200<br>2. 用户状态为已激活<br>3. 无需邮箱激活即可登录 | `SELECT status FROM users WHERE username='xxx'` 返回 `1` |
| REG-002 | 管理员创建用户并设置初始状态为未激活 | 管理员已登录 | 1. 管理员创建用户，status=0（未激活）<br>2. 提交表单 | 1. API 返回 200<br>2. 用户状态为未激活<br>3. 用户无法登录 | `SELECT status FROM users WHERE username='xxx'` 返回 `0` |
| REG-003 | 用户自助注册流程状态正确 | 系统无管理员 | 1. 用户填写注册表单<br>2. 提交注册 | 1. 创建用户，status=0（未激活）<br>2. 发送激活邮件 | `SELECT status FROM users WHERE email='xxx'` 返回 `0` |
| REG-004 | 重复用户名注册拒绝 | 无 | 1. 创建用户 "testuser"<br>2. 再次创建相同用户名 | 返回错误：用户名已存在 | 用户表仅有一条 username='testuser' 的记录 |
| REG-005 | 创建用户时分配角色 | 存在可用角色 | 1. 创建用户并分配 role_ids=[2,3]<br>2. 查询用户角色 | 1. API 返回成功<br>2. 用户拥有指定角色 | `SELECT role_id FROM user_roles WHERE user_id=xxx` 包含 2,3 |

### 1.2 用户状态变更

**测试目标**：验证用户状态（激活/锁定/禁用）变更的正确性及对登录的影响

| 用例编号 | 用例描述 | 测试步骤 | 预期结果 | 数据库验证 |
|---------|---------|---------|---------|-----------|
| STA-001 | 管理员禁用用户后用户无法登录 | 1. 禁用用户（status=3）<br>2. 用户尝试登录 | 登录失败，提示"账号已禁用" | `SELECT status FROM users WHERE id=xxx` 返回 `3` |
| STA-002 | 管理员锁定用户后用户无法登录 | 1. 锁定用户（status=2）<br>2. 用户尝试登录 | 登录失败，提示"账号已锁定" | `SELECT status FROM users WHERE id=xxx` 返回 `2` |
| STA-003 | 管理员解锁用户后用户恢复登录 | 1. 用户当前 status=2<br>2. 管理员更新为 status=1 | 1. 更新成功<br>2. 用户可正常登录 | `SELECT status FROM users WHERE id=xxx` 返回 `1` |
| STA-004 | 管理员激活未激活用户 | 1. 用户当前 status=0<br>2. 管理员激活用户 | 1. 更新成功<br>2. 用户可正常登录 | `SELECT status FROM users WHERE id=xxx` 返回 `1` |
| STA-005 | 批量更新用户状态 | 1. 选择 5 个用户<br>2. 批量禁用 | 1. 全部更新成功<br>2. 所有用户 status=3 | `SELECT COUNT(*) FROM users WHERE status=3 AND id IN (...)` 返回 `5` |

### 1.3 用户删除

**测试目标**：验证用户删除后的数据完整性

| 用例编号 | 用例描述 | 测试步骤 | 预期结果 | 数据库验证 |
|---------|---------|---------|---------|-----------|
| DEL-001 | 删除用户后用户角色关联清除 | 1. 删除用户 ID=10<br>2. 查询 user_roles | 1. API 返回 200<br>2. 该用户无角色记录 | `SELECT COUNT(*) FROM user_roles WHERE user_id=10` 返回 `0` |
| DEL-002 | 删除用户后登录日志保留用户ID | 1. 删除用户前查询登录日志<br>2. 删除用户<br>3. 查询登录日志 | 1. 删除前有日志<br>2. 删除后日志仍存在，user_id 字段保留 | 登录日志表 user_id 字段保留原值（非级联删除） |
| DEL-003 | 删除用户后设备关联保留 | 1. 删除用户<br>2. 查询 devices 表 | devices 表中该用户的设备保留，user_id 不变 | `SELECT COUNT(*) FROM devices WHERE user_id=xxx` 结果不变 |
| DEL-004 | 恢复删除（软删除）的用户 | 1. 系统启用软删除<br>2. 删除用户<br>3. 恢复用户 | 1. 删除成功<br>2. 恢复后用户状态恢复 | 用户记录恢复，status 恢复原值 |

---

## 2. 统计数据正确性测试

### 2.1 用户统计正确性

**测试目标**：验证用户统计（total_users, active_users, new_users 等）的计算正确性

| 用例编号 | 用例描述 | 测试步骤 | 预期结果 | 数据库验证 |
|---------|---------|---------|---------|-----------|
| STAT-001 | 总用户数统计正确 | 1. 查询当前总用户数<br>2. 创建 3 个新用户<br>3. 再次查询 | 第二次查询比第一次多 3 | `SELECT COUNT(*) FROM users` 与 API 返回 total_users 一致 |
| STAT-002 | 新增用户今日统计正确 | 1. 查看今日新增<br>2. 创建一个用户<br>3. 再次查看 | 新增用户数 +1 | `SELECT COUNT(*) FROM users WHERE created_at >= today_start` 与 new_users_today 一致 |
| STAT-003 | 按状态统计正确 | 1. 创建 2 个用户后禁用其中一个<br>2. 查询统计数据 | disabled_users = 1 | `SELECT COUNT(*) FROM users WHERE status=3` 与 disabled_users 一致 |
| STAT-004 | 创建用户后 dashboard 统计数据更新 | 1. 获取 dashboard stats<br>2. 创建 1 个用户<br>3. 再次获取 | total_users +1, new_users_today +1 | 两次 stats 对比差异正确 |
| STAT-005 | 删除用户后统计更新 | 1. 获取 stats<br>2. 删除 1 个用户<br>3. 再次获取 | total_users -1 | 两次 stats 对比差异正确 |
| STAT-006 | 批量创建用户统计准确 | 1. 批量导入 100 个用户<br>2. 查询统计 | total_users 增加 100 | `SELECT COUNT(*) FROM users` 增加 100 |

### 2.2 登录统计正确性

**测试目标**：验证登录成功/失败次数统计的正确性

| 用例编号 | 用例描述 | 测试步骤 | 预期结果 | 数据库验证 |
|---------|---------|---------|---------|-----------|
| LOGIN-001 | 登录成功日志记录正确 | 1. 用户成功登录<br>2. 查询登录日志 | 1. 日志存在<br>2. status=1（成功）<br>3. user_id 正确 | `SELECT status, user_id FROM login_logs ORDER BY id DESC LIMIT 1` |
| LOGIN-002 | 登录失败日志记录正确 | 1. 用户使用错误密码登录<br>2. 查询登录日志 | 1. 日志存在<br>2. status=0（失败）<br>3. fail_reason 包含原因 | `SELECT status, fail_reason FROM login_logs ORDER BY id DESC LIMIT 1` |
| LOGIN-003 | 登录统计今日成功次数正确 | 1. 查询 logins_today_success<br>2. 3 个用户成功登录<br>3. 再次查询 | 第二次比第一次多 3 | `SELECT COUNT(*) FROM login_logs WHERE status=1 AND created_at >= today_start` |
| LOGIN-004 | 登录统计今日失败次数正确 | 1. 查询 logins_today_failed<br>2. 2 个用户密码错误登录失败<br>3. 再次查询 | 第二次比第一次多 2 | `SELECT COUNT(*) FROM login_logs WHERE status=0 AND created_at >= today_start` |

---

## 3. 设备信任管理正确性测试

### 3.1 设备信任状态变更

**测试目标**：验证设备信任/取消信任操作的正确性

| 用例编号 | 用例描述 | 测试步骤 | 预期结果 | 数据库验证 |
|---------|---------|---------|---------|-----------|
| DEV-001 | 用户信任当前设备 | 1. 用户登录新设备<br>2. 调用信任设备接口<br>3. 查询设备 | 1. API 返回 200<br>2. is_trusted=true<br>3. trust_expires_at 有值 | `SELECT is_trusted, trust_expires_at FROM devices WHERE id=xxx` |
| DEV-002 | 用户取消信任设备 | 1. 设备 is_trusted=true<br>2. 调用取消信任<br>3. 查询设备 | 1. API 返回 200<br>2. is_trusted=false<br>3. trust_expires_at=null | 同上，is_trusted=false |
| DEV-003 | 管理员信任任意设备 | 1. 管理员调用 adminTrustDevice<br>2. 查询设备 | is_trusted=true, trust_expires_at 为 30 天后 | 同上 |
| DEV-004 | 管理员取消信任任意设备 | 1. 管理员调用 adminUntrustDevice<br>2. 查询设备 | is_trusted=false | 同上 |
| DEV-005 | 管理员删除设备 | 1. 管理员调用 adminDeleteDevice<br>2. 查询设备 | 设备不存在 | `SELECT COUNT(*) FROM devices WHERE id=xxx` 返回 0 |
| DEV-006 | 信任过期后状态正确 | 1. 设置 trust_expires_at 为过去时间<br>2. 查询设备状态 | is_trusted=false（过期检查逻辑） | `SELECT is_trusted FROM devices WHERE trust_expires_at < now()` |

### 3.2 设备与用户关联正确性

| 用例编号 | 用例描述 | 测试步骤 | 预期结果 | 数据库验证 |
|---------|---------|---------|---------|-----------|
| DEV-007 | 设备正确归属用户 | 1. 用户 A 登录设备<br>2. 用户 B 查看自己的设备 | 1. 设备属于用户 A<br>2. 用户 B 看不到 | devices 表 user_id 字段正确 |
| DEV-008 | 管理员查看所有设备 | 1. 管理员调用 listAllDevices<br>2. 查看返回列表 | 包含所有用户的设备 | `SELECT COUNT(*) FROM devices` 与返回 total 一致 |
| DEV-009 | 管理员按用户筛选设备 | 1. 设置 user_id_filter=5<br>2. 调用 listAllDevices | 仅返回 user_id=5 的设备 | SQL: `WHERE user_id=5` |

---

## 4. 权限与角色正确性测试

### 4.1 角色分配正确性

| 用例编号 | 用例描述 | 测试步骤 | 预期结果 | 数据库验证 |
|---------|---------|---------|---------|-----------|
| ROLE-001 | 分配角色后用户拥有对应权限 | 1. 用户无角色<br>2. 分配 role_id=2<br>3. 验证用户权限 | 用户拥有 role_id=2 的所有权限 | `SELECT permission_id FROM role_permissions WHERE role_id=2` 与用户实际权限对比 |
| ROLE-002 | 分配多个角色权限合并 | 1. 分配 role_ids=[2,3]<br>2. 验证用户权限 | 用户拥有 role 2 和 role 3 的所有权限并集 | 权限数量 = role2 权限数 + role3 权限数（去重） |
| ROLE-003 | 移除用户角色 | 1. 用户有角色<br>2. 移除角色<br>3. 验证权限减少 | 用户失去被移除角色的权限 | 移除前后的权限数量对比 |
| ROLE-004 | 角色状态为禁用时用户无该角色权限 | 1. 角色 status=0（禁用）<br>2. 用户拥有该角色<br>3. 验证权限 | 用户不拥有该角色的任何权限 | 权限检查跳过 status=0 的角色 |

### 4.2 权限继承正确性

| 用例编号 | 用例描述 | 测试步骤 | 预期结果 | 数据库验证 |
|---------|---------|---------|---------|-----------|
| PERM-001 | 子权限继承父权限 | 1. 权限 A 是权限 B 的父级<br>2. 用户拥有 A<br>3. 检查 B 的访问 | 用户同时拥有 A 和 B | 权限树结构验证 |
| PERM-002 | 权限树深度遍历正确 | 1. 用户拥有叶节点权限<br>2. 检查所有祖先权限 | 用户拥有完整路径上的所有权限 | 递归查询权限树 |

---

## 5. 前端行为与后端数据一致性

### 5.1 表单提交与数据库

| 用例编号 | 用例描述 | 测试步骤 | 预期结果 |
|---------|---------|---------|---------|
| FE-001 | 创建用户表单提交后数据库正确 | 1. 填写用户名、邮箱、密码<br>2. 提交<br>3. 页面刷新后数据存在 | 数据库用户表有一条对应记录 |
| FE-002 | 编辑用户信息后数据库同步 | 1. 修改用户昵称<br>2. 保存<br>3. 重新加载页面 | 数据库 nickname 字段已更新 |
| FE-003 | 删除用户后列表刷新 | 1. 删除用户<br>2. 页面自动刷新 | 列表中不再显示该用户，数据库中已删除 |
| FE-004 | 筛选条件变更后列表正确 | 1. 选择"仅活跃用户"<br>2. 查看列表 | 仅显示 status=1 的用户 |

### 5.2 批量操作一致性

| 用例编号 | 用例描述 | 测试步骤 | 预期结果 |
|---------|---------|---------|---------|
| FE-005 | 批量启用用户后数据库一致 | 1. 选中 10 个用户<br>2. 批量启用<br>3. 刷新页面 | 10 个用户 status=1 |
| FE-006 | 批量导入用户后统计正确 | 1. 导入 CSV（50 个用户）<br>2. 查看统计 | total_users 增加 50 |
| FE-007 | 批量导出数据完整 | 1. 导出当前用户列表<br>2. 比对记录数 | 导出数量 = 数据库实际数量 |

---

## 6. 测试数据准备脚本

### 6.1 用户统计测试数据准备

```sql
-- 清理测试数据
DELETE FROM users WHERE username LIKE 'stat_test_%';

-- 插入不同状态的用户
INSERT INTO users (username, email, password, status, created_at) VALUES
  ('stat_test_active_1', 'active1@test.com', '$2a$10$...', 1, NOW()),
  ('stat_test_active_2', 'active2@test.com', '$2a$10$...', 1, NOW()),
  ('stat_test_locked', 'locked@test.com', '$2a$10$...', 2, NOW()),
  ('stat_test_disabled', 'disabled@test.com', '$2a$10$...', 3, NOW()),
  ('stat_test_inactive', 'inactive@test.com', '$2a$10$...', 0, NOW() - INTERVAL '2 days');
```

### 6.2 登录日志测试数据准备

```sql
-- 清理测试数据
DELETE FROM login_logs WHERE user_id IN (SELECT id FROM users WHERE username LIKE 'login_test_%');

-- 准备测试用户
INSERT INTO users (username, email, password, status) VALUES
  ('login_test_user', 'logintest@test.com', '$2a$10$...', 1);

-- 插入登录日志
INSERT INTO login_logs (user_id, login_type, status, ip, created_at) VALUES
  (currval('users_id_seq'), 1, 1, '192.168.1.1', NOW()),
  (currval('users_id_seq'), 1, 0, '192.168.1.2', NOW() - INTERVAL '1 hour'),
  (currval('users_id_seq'), 1, 1, '192.168.1.3', NOW() - INTERVAL '2 hours');
```

---

## 7. 测试执行检查清单

### 7.1 测试前检查

- [ ] 测试数据库已初始化
- [ ] 测试用户已创建（有管理员权限）
- [ ] API 服务运行正常
- [ ] 前端开发服务器运行正常

### 7.2 测试后清理

- [ ] 测试数据已清理
- [ ] 无残留测试用户
- [ ] 统计数据已恢复

### 7.3 成功标准

- [ ] 所有测试用例通过
- [ ] 数据库验证全部符合预期
- [ ] 前端行为与数据库状态一致
- [ ] 统计数据计算误差为 0
