聚焦“异常日志”与“单元测试”交叉难点,重点掌握:日志级别匹配、关键信息记录、异常对象传参;用Mockito或内存Appender验证被吞异常;依规范反推测试点,写硬核断言验证日志内容。

直接聚焦“异常日志”和“单元测试”两个交叉难点来复习,效果最实。重点不是背概念,而是搞清:异常被吃掉后怎么测?日志里写了什么才算处理到位?
抓准异常日志的测试靶心
很多代码把异常 catch 住、打个 log 就完事,比如:
logger.error("查询失败", e);
这种写法看似稳妥,但测试时容易漏掉关键点。复习时要盯住三件事:
- 日志级别是否匹配异常严重性(如空指针用 error,参数校验失败用 warn)
- 日志消息是否包含可定位的关键信息(如方法名、ID、状态码)
- 异常对象是否作为第二个参数传入(否则堆栈丢失,log 里看不到 trace)
验证“被吞掉”的异常,不靠 assertThrows
当 methodB() 抛异常又被自己 catch + log,assertThrows 就完全失效——因为方法正常返回了,没抛出任何东西。这时候得换思路:
- 用 Mockito 模拟 Logger,验证 logger.error() 是否被调用过,且参数含预期异常
- 把日志输出重定向到内存 Appender(如 ListAppender),断言日志列表里有对应条目
- 优先考虑重构:把异常处理逻辑抽成 protected 方法,测试子类中该方法是否被调用
结合规范,反推测试覆盖点
翻一翻《阿里巴巴Java开发规范》里关于异常日志的条款,能快速锁定必须测的场景:
- 捕获 RuntimeException(如 NPE)却没做预检 → 测试应触发该异常,并确认日志里有 warning 或 error
- catch 后只打日志、不 re-throw 也不返回兜底值 → 测试需检查业务结果是否合理(比如查不到数据是否返回空集合而非 null)
- finally 中关闭资源但没 try-catch → 测试要制造资源关闭失败,验证是否有二次异常被吞
用真实断言代替“看起来没问题”
别只看测试通过就放心。复习时亲手写几条硬核断言:
- 验证日志中是否包含异常类名:
logOutput.contains("NullPointerException") - 验证是否记录了关键业务字段:
logOutput.contains("orderId=12345") - 验证错误码是否统一:
logOutput.matches("ERR_\d{4}")
这些细节才是线上出问题时真正能救命的证据。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











