如何Mock静态非void方法使其两次调用表现不同?
Mock静态方法实现首次抛异常、二次返回指定值及调用验证
我需要Mock一个静态方法,让它第一次调用时抛出异常,第二次调用时返回指定值。我知道单独Mock抛异常或返回值的方法,但不知道怎么让它在连续两次调用中表现不同。
同时,我该如何在单个测试中验证对Mock静态方法的两次连续调用?能不能在一个MockedStatic代码块里实现,还是需要为每次调用分别用不同的MockedStatic代码块?以下是示例代码:
/** 包含待Mock静态方法的工具类 */ public final class VariableUtil { // 待Mock的静态方法 public static JsonValue createJsonVariable(Object variableValue) throws Exception{…..} } /** JsonValue接口 */ public interface JsonValue extends PrimitiveValue<String> { } /** 使用VariableUtil的业务类 */ public class SomeClass { // 调用两次静态方法的业务方法 public void someMethod() { try { // 第一次调用静态方法,预期抛出异常 VariableUtil.createJsonVariable( Collections.singletonList(someObject)); } catch(Exception ex) { // 捕获异常后第二次调用静态方法,预期返回Mock值 JsonValue someJsonValue = VariableUtil.createJsonVariable( Collections.singletonList(someObject)); } } } /** JUnit测试类 */ @Test public void testCreateVariable() { // 下面的写法不生效,怎么Mock才能让第一次调用抛异常、第二次返回值? try (final MockedStatic<VariableUtil> variableUtilMock = // Mock抛出异常 mockStatic(VariableUtil.class)) { variableUtilMock.when(() -> VariableUtil.createJsonVariable(processingFailureErrorMessage)) .thenThrow(new Exception()); // Mock返回值 variableUtilMock.when(() -> VariableUtil.createJsonVariable(processingFailureErrorMessage)) .thenReturn("someJsonValue"); SomeClass someObject = new SomeClass(); someObject.someMethod(); } }
解决方案
1. 实现连续调用的不同行为
你完全可以在同一个MockedStatic代码块里实现需求,无需拆分。Mockito提供了两种简单方式:
方式一:链式指定调用顺序
直接通过thenThrow().thenReturn()的链式调用,按调用顺序定义行为:
@Test public void testCreateVariable() { // 提前Mock一个JsonValue实例(因为JsonValue是接口,需要Mock实现) JsonValue mockJsonValue = Mockito.mock(JsonValue.class); try (final MockedStatic<VariableUtil> variableUtilMock = Mockito.mockStatic(VariableUtil.class)) { // 第一次调用抛异常,第二次返回Mock实例 variableUtilMock.when(() -> VariableUtil.createJsonVariable(processingFailureErrorMessage)) .thenThrow(new Exception()) .thenReturn(mockJsonValue); SomeClass someClass = new SomeClass(); someClass.someMethod(); // 验证静态方法被调用了两次 variableUtilMock.verify(() -> VariableUtil.createJsonVariable(processingFailureErrorMessage), Mockito.times(2)); } }
方式二:自定义Answer逻辑(适用于复杂场景)
如果需要更灵活的调用控制,可以用thenAnswer结合计数器实现:
@Test public void testCreateVariableWithCustomAnswer() { AtomicInteger callCounter = new AtomicInteger(0); JsonValue mockJsonValue = Mockito.mock(JsonValue.class); try (final MockedStatic<VariableUtil> variableUtilMock = Mockito.mockStatic(VariableUtil.class)) { variableUtilMock.when(() -> VariableUtil.createJsonVariable(processingFailureErrorMessage)) .thenAnswer(invocation -> { int currentCall = callCounter.incrementAndGet(); if (currentCall == 1) { throw new Exception(); } else { return mockJsonValue; } }); SomeClass someClass = new SomeClass(); someClass.someMethod(); // 验证调用次数 variableUtilMock.verify(() -> VariableUtil.createJsonVariable(processingFailureErrorMessage), Mockito.times(2)); } }
2. 关键注意事项
- 无需拆分MockedStatic块:同一个
try-with-resources声明的MockedStatic会覆盖整个测试方法内的静态方法调用,两次调用都在同一Mock控制下。 - 参数匹配一致性:
when和verify中的参数要完全匹配(比如processingFailureErrorMessage要和业务方法中传入的参数一致),如果需要放宽匹配条件,可以用Mockito.any()等匹配器。 - Mock接口实例:因为
JsonValue是接口,不能直接返回字符串,需要用Mockito.mock(JsonValue.class)创建Mock实例。
内容的提问来源于stack exchange,提问作者Sandeep Barnabas
相关产品推荐
相关产品推荐

