自动化与脚本
用 JUnit 5 + Mockito 单元测试…
在不启动完整 Spring 容器的前提下,对 Spring ApplicationEvent 的发布者与 @EventListener 消费者编写单元测试。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 49/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
用 JUnit 5 + Mockito 通用
解决思路
- 添加测试依赖:spring-boot-starter、JUnit 5、Mockito、AssertJ(Maven 用 <scope>test</scope>,Gradle 用 testImplementation)。
- 在待测服务中用 @Mock 注解 ApplicationEventPublisher 字段,避免事件真正发布到 Spring 上下文。
- 用 ArgumentCaptor.forClass(EventType.class) 捕获发布的事件,检查 payload 内容。
- 直接调用监听器方法并传入 mock 依赖,验证监听器的副作用(如发送邮件)。
- 测试异步处理器(@Async + @EventListener)时,用 Thread.sleep() 或 Awaitility 等待后断言异步操作被调用。
- 加入校验检查点:捕获事件后先确认 eventCaptor.getValue() 不为 null 再断言字段;若监听器未被调用,则验证 publishEvent() 是否以正确事件类型被调用;若异步断言失败,增加等待时间并检查执行器线程池是否饱和。
- 覆盖错误场景:断言监听器能优雅处理异常,不向发布者传播异常。
- 最佳实践:mock ApplicationEventPublisher,绝不让其在单元测试中投递到真实上下文。
- 用 ArgumentCaptor 捕获事件并做字段级相等断言,而不仅是类型断言。
- 隔离测试监听器:用 mock 依赖构造监听器并直接调用处理方法。
- 覆盖错误路径:监听器不得把异常传播给发布者。
- 异步监听器优先使用 Awaitility 而非 Thread.sleep(),以获得确定性的等待。
- 保持事件不可变且可序列化;若事件跨 JVM 边界,需同时测试这两点。
- 不要测试 Spring 自身的事件基础设施,聚焦业务逻辑与事件 payload。
- 注意 @Async 需要 @EnableAsync;使用 Thread.sleep 的测试即使异步代理未接入也可能通过,应改用 mock verify。
- Spring 不保证监听器顺序,除非加 @Order,否则不要编写依赖执行顺序的测试。
- 避免在 CI 环境中使用 Thread.sleep(),负载下会导致测试不稳定,改用 Awaitility 的 .atMost() 块。
- 跨 JVM 边界的事件需要序列化测试;远程监听器中字段为 null 通常意味着缺少 Serializable。
适用边界 · 注意事项
- 不要测试 Spring 自身的事件基础设施,应聚焦业务逻辑与事件 payload。
- 不要编写依赖监听器执行顺序的测试,除非显式添加 @Order。
- 不要在 CI 环境中使用 Thread.sleep() 等待异步结果,应改用 Awaitility。