4.1 KiB
4.1 KiB
07 — 测试与错误处理规则
适用:所有后端开发任务。AI 最容易忽略的两件事:写测试、统一错误码。
测试规则
必须写测试的场景
| 场景 | 测试类型 | 要求 |
|---|---|---|
| 新增 Service 方法 | 单元测试 | 必须 |
| 新增 Controller 接口 | 集成测试 | 必须 |
| 涉及金额计算 | 单元测试 | 必须(多组边界值) |
| 涉及状态流转 | 单元测试 | 必须(覆盖所有状态路径) |
| 涉及外部接口调用 | 集成测试 | 必须(Mock 外部依赖) |
| 修 Bug | 回归测试 | 必须(防止复现) |
| 简单 CRUD | 可选 | 不强制 |
AI 测试规则
AI 完成任务后,必须同时交付测试代码。 禁止说"功能写好了但测试你自己补"。
// ✅ AI 必须产出完整测试
@SpringBootTest
class TaskServiceTest {
@Autowired
private TaskService taskService;
@Test
void shouldCreateTask() { ... }
@Test
void shouldNotCreateTaskWithoutTitle() { ... }
@Test
void shouldCalculateRewardCorrectly() { ... }
}
// ❌ AI 不能这样
// "功能已完成,测试代码未编写,建议后续补充"
测试命名
方法名_场景_预期结果
shouldCreateTask_whenValidInput
shouldNotCreateTask_whenTitleIsEmpty
shouldCalculateReward_whenDiscountApplied
shouldReturnFail_whenTaskNotFound
禁止
- 测试只测正常路径,不测异常路径
- 测试依赖执行顺序(每个测试必须独立)
- 测试里有
Thread.sleep()(用 Awaitility) - 测试代码复制粘贴业务代码(测了个寂寞)
错误处理规则
返回格式(不变式)
// ✅ 统一返回
Result.ok(data) // 成功
Result.error("原因") // 业务失败(用户可见)
Result.error("系统错误") // 系统异常(用户不可见,只记录日志)
// JSON 格式
{ "code": 200, "message": "success", "data": {...} } // 成功
{ "code": 500, "message": "任务不存在", "data": null } // 业务失败
{ "code": 500, "message": "系统繁忙,请稍后重试", "data": null } // 系统异常
什么情况返回什么
// 查不到 → 业务失败
if (task == null) return Result.error("任务不存在");
// 参数不合法 → 业务失败
if (page < 1) return Result.error("页码必须大于0");
// 没权限 → 业务失败
if (!hasPermission) return Result.error("无权操作");
// 数据库连接失败 → 系统异常(全局异常处理器统一捕获)
// 第三方接口超时 → 系统异常(记录日志 + 返回通用错误)
// 不需要手动 try-catch 每个地方,用全局异常处理器统一处理
全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public Result<?> handleBusiness(BusinessException e) {
log.warn("业务异常: {}", e.getMessage());
return Result.error(e.getMessage()); // 用户可见
}
@ExceptionHandler(Exception.class)
public Result<?> handleException(Exception e) {
log.error("系统异常", e);
return Result.error("系统繁忙,请稍后重试"); // 用户不可见原文
}
}
禁止
| ❌ | ✅ |
|---|---|
return Result.error(e.getMessage()) 把栈打印给用户 |
return Result.error("任务不存在") |
| 每个方法都 try-catch 一遍 | 全局异常处理器统一处理 |
异常被吞掉 catch(Exception e) {} |
至少打日志 log.error("xxx", e) |
return null 让前端爆 NPE |
return Result.error("原因") |
| 成功和失败都用 code=200 | 失败用 code=500 |
检查表
测试
- 新增的非 CRUD 方法有测试
- 测试覆盖了异常路径(不是只测正常路径)
- 金额计算有边界值测试
- AI 交付包含测试代码
错误处理
- 错误信息用户能看懂(不是技术术语)
- 系统异常不暴露内部信息给用户
- 查不到/null 有明确 fail 返回
- 没有空 catch 块
- 没有
return null代替错误返回