1. 概述
在本教程中,我们将介绍 Mockito 的静态方法 - mock的各种用法。
与本站的其他 Mockito 框架的文章一样(如 Mockito Verify 或 Mockito When/Then,我们将使用下面的 MyList 类将作为本文的测试用例:
public class MyList extends AbstractList<String> {
@Override
public String get(int index) {
return null;
}
@Override
public int size() {
return 1;
}
}
2. 简单mock
mock 有好几个重载方法,最简单的一个只需传入被mock 的class
public static <T> T mock(Class<T> classToMock)
我们将使用此方法来mock一个类,并设置一个期望值:
MyList listMock = mock(MyList.class);
when(listMock.add(anyString())).thenReturn(false);
然后,我们在 mock 的对象上执行一个方法:
boolean added = listMock.add(randomAlphabetic(6));
下面的测试用代码,确认了我们调用了 mock 上的 add 方法。调用返回的值与我们之前设定的期望值一致:
verify(listMock).add(anyString());
assertThat(added).isFalse();
3. 指定Mock的名字
在本节中,我们将介绍 mock 的第二个重载方法,第二个参数指定了 mock 的名称:
public static <T> T mock(Class<T> classToMock, String name)
一般来说,这个名字没啥用。不过,它在调试时可能会有所帮助,因为我们会使用 mock 的名字来追踪错误。
为了确保验证不成功时抛出的异常信息中包含所提供的 mock 名称,我们将使用 assertThatThrownBy. 来进行验证。 在下面的代码中,我们将为 MyList 类创建一个 mock,并将其命名为 myMock:
MyList listMock = mock(MyList.class, "myMock");
然后,我们将对 mock 的方法设置期望值并执行它:
when(listMock.add(anyString())).thenReturn(false);
listMock.add(randomAlphabetic(6));
接下来,我们将在 assertThatThrownBy 中调用验证,并验证所抛出异常的实例:
assertThatThrownBy(() -> verify(listMock, times(2)).add(anyString()))
.isInstanceOf(TooFewActualInvocations.class)
此外,我们还可以验证异常信息是否包含有关mock的信息:
assertThatThrownBy(() -> verify(listMock, times(2)).add(anyString()))
.isInstanceOf(TooFewActualInvocations.class)
.hasMessageContaining("myMock.add");
下面是抛出的异常信息:
org.mockito.exceptions.verification.TooLittleActualInvocations:
myMock.add(<any>);
Wanted 2 times:
at com.baeldung.mockito.MockitoMockTest
.whenUsingMockWithName_thenCorrect(MockitoMockTest.java:...)
but was 1 time:
at com.baeldung.mockito.MockitoMockTest
.whenUsingMockWithName_thenCorrect(MockitoMockTest.java:...)
我们可以看到,异常消息中包含了mock的名称,这将有助于在验证不成功时找到故障点。
4. 自定义Answer
在这里,我们将演示 mock 的另一个重载方法,其中我们将在创建时配置mock对交互的answer的策略。 该方法的定义如下所示:
public static <T> T mock(Class<T> classToMock, Answer defaultAnswer)
让我们从 Answer 接口的实现定义开始:
class CustomAnswer implements Answer<Boolean> {
@Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
return false;
}
}
我们将使用上面的 CustomAnswer 类来生成mock:
MyList listMock = mock(MyList.class, new CustomAnswer());
如果我们不对方法设置期望值,CustomAnswer类型配置的默认answer就会发挥作用。为了证明这一点,我们将跳过设置期望值的步骤,直接执行方法:
boolean added = listMock.add(randomAlphabetic(6));
下面的验证和断言确认了带有 Answer 参数的 mock 方法按预期运行:
verify(listMock).add(anyString());
assertThat(added).isFalse();
5. MockSettings
本文要介绍的最后一个 mock 方法是带有 MockSettings 参数的重载方法。我们使用这个重载方法来提供一个非标准的mock。
MockSettings 接口的方法支持多种自定义设置,例如使用 invocationListeners 为当前 mock 上的方法调用注册监听器、使用 serializable 配置序列化、使用 spiedInstance 指定要监视的实例、使用 useConstructor 配置 Mockito 在实例化 mock 时尝试使用构造函数等。
为了方便起见,我们将重复使用上一节介绍的 CustomAnswer 类,创建一个 MockSettings 实现,定义默认answer。
MockSettings 对象由工厂方法实例化:
MockSettings customSettings = withSettings().defaultAnswer(new CustomAnswer());
我们将在创建新的mock时使用该设置对象:
MyList listMock = mock(MyList.class, customSettings);
与上一节类似,我们将调用 MyList 实例的 add 方法,并验证带有 MockSettings 参数的 mock 方法是否按预期运行:
boolean added = listMock.add(randomAlphabetic(6));
verify(listMock).add(anyString());
assertThat(added).isFalse();
6. 总结
在本文中,我们详细介绍了 Mockito 的 mock 方法。这些示例和代码片段的实现可以在 GitHub 中找到。