单元测试:如何验证被测void方法是否以正确参数调用了其他方法
解决方案
你之前测试失效的核心原因:Util.createEvent()是静态方法,普通Mockito的@Mock只能mock类的实例对象,无法拦截静态方法的调用,因此verify和ArgumentCaptor都不会生效。
下面提供两种可行方案:
方案1:使用Mockito静态mock能力(无需修改业务代码)
要求Mockito版本≥3.4.0,同时需要引入mockito-inline依赖(默认Mockito不支持静态mock,需要这个扩展)。
步骤1:引入依赖
如果是Maven项目,在pom.xml中添加:
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-inline</artifactId> <version>你的Mockito版本号</version> <scope>test</scope> </dependency>
步骤2:编写单元测试示例
以下是验证code为SUCCESS场景下参数的测试用例:
import org.mockito.MockedStatic; import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.times; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyMap; // 测试类代码 @Test void testOnMessageSuccessScenario() { // 1. 先模拟codeMagicThatDoesntConcernUsCurrently返回SUCCESS的逻辑,自行实现打桩逻辑 // 2. 打开Util类的静态mock,用try-with-resources自动关闭 try (MockedStatic<Util> mockedUtil = mockStatic(Util.class)) { // 3. 调用待测试的方法 messageHandler.OnMessage(); // 4. 验证静态方法调用的参数是否符合预期 mockedUtil.verify( () -> Util.createEvent( anyString(), eq(enumStatusObject.SUCCESS), anyMap() ), times(1) ); // 如果需要捕获参数做更复杂的校验,可以用ArgumentCaptor ArgumentCaptor<enumStatusObject> statusCaptor = ArgumentCaptor.forClass(enumStatusObject.class); mockedUtil.verify( () -> Util.createEvent(anyString(), statusCaptor.capture(), anyMap()), times(1) ); Assert.assertEquals(enumStatusObject.SUCCESS, statusCaptor.getValue()); } }
对应不同分支场景只需修改打桩的code返回值,以及verify时匹配的枚举值即可:
- code非SUCCESS场景:校验传入参数为
enumStatusObject.ERROR - 异常场景:校验传入参数为
enumStatusObject.EXCEPTION
方案2:优化业务代码消除静态依赖(更推荐,长期可维护性更高)
静态方法会导致强耦合、难测试,你可以通过依赖注入的方式改造代码,避免使用静态方法:
- 将
Util类改为普通的Bean/组件,或者封装一层非静态的Wrapper类 - 在
MessageHandler中通过构造函数/Setter注入Util实例 - 测试时直接用普通的
@Mock注解mockUtil实例,你之前写的verify写法即可生效。
改造后的业务代码示例:
public class MessageHandler { // 注入Util实例,而非调用静态方法 private final Util util; // 构造函数注入 public MessageHandler(Util util) { this.util = util; } public void OnMessage() { // ... 原有逻辑 if (!"SUCCESS".equals(code)) { // 调用实例方法而非静态方法 util.createEvent(stringVariable, enumStatusObject.ERROR, mapPayload); log.info("oh no!"); throw new RuntimeException(); } // ... 其余逻辑 } }
改造后你之前写的verify(util, times(1)).createEvent(anyString(), eq(enumStatusObject.SUCCESS), anyMap());就可以正常生效。
内容的提问来源于stack exchange,提问作者infiniteLoopLife9
相关产品推荐
相关产品推荐

