Appearance
Mockito
本文介绍Mockito框架。
1. 测试替身
在软件开发中,**测试替身(Test Double)**是一个通用的术语,用来指代那些在测试中为了替换真实对象而创建的“伪造”对象。
就像电影拍摄中使用替身演员来完成危险动作或节省成本一样,程序测试中使用“替身”来隔离被测代码,解决依赖项难以操作、速度慢或不可控的问题。
为什么要用测试替身?
- 隔离外部依赖:比如数据库、第三方 API 或文件系统。
- 提高测试速度:真实的数据库操作很慢,替身数据库在内存中运行,速度极快。
- 模拟极端情况:比如模拟网络超时、服务器 500 错误等真实环境难以复现的场景。
- 确定性:真实环境(如获取当前时间)是变化的,替身可以返回固定的值。
测试替身可以分为以下五种:
- Dummy(哑物):最简单的替身。它只是为了填充参数列表而存在,永远不会被真正调用或使用。
- 场景:某个方法需要传 3 个参数,但测试的功能只涉及前 2 个,因此,第三个参数使用Dummy测试替身填充。
- Stub(桩):为测试提供固定的答案。它实现了接口,但内部逻辑是死代码,只返回预定义好的数据。
- 场景:模拟获取天气,无论真实天气如何,Stub 永远返回“晴天”。
- Spy(间谍):它会记录自己被调用的情况。它不仅能返回数据,还会偷偷记下谁调用了它、传了什么参数、调用了几次。
- 场景:测试发送邮件功能,通过 Spy 确认
send()方法确实被触发了一次。
- 场景:测试发送邮件功能,通过 Spy 确认
- Mock (模拟对象):这是最容易被误用的词。Mock的核心在于行为验证。假如预先设定:“期望这个对象被调用 A 方法,参数是 B,返回 C”。如果测试结束时这些期望没达成,测试就失败。
- 场景:验证转账功能中,银行接口必须且只能被调用一次。
- Fake (伪对象):Fake拥有简化版的业务逻辑,它确实能工作,但因为性能或环境限制,不适合用于生产环境。
- 场景:内存数据库(如 H2)代替真实的 MySQL;用一个简单的
Map代替复杂的Redis 缓存。
- 场景:内存数据库(如 H2)代替真实的 MySQL;用一个简单的
Mockito框架就是用于构造测试替身的。
2. Mockito
2.1 基本使用
首先引入依赖:
xml
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.22.0</version>
</dependency>然后,在测试代码中就可以按照以下步骤使用Mockito了:
- 创建测试替身:也就是对于真实对象,创建出一个替身对象来,之后的操作都是在替身对象上进行;
- 打桩:定义当调用替身对象的某个方法时,该方法应该执行什么逻辑、返回什么值;
- 执行:在替身对象上执行某个操作,即调用某个方法(一般都是打什么桩就调用什么方法);
- 验证:验证在替身对象上调用的方法参数、次数等;
案例:假设现在有一个功能,当用户点击“立即下单”时,业务系统调用第三方快递公司(如顺丰、菜鸟)的 API 来下快递单,并获取单号。但是,在测试中,我们不想真的去调用快递公司的接口(那会产生真实订单和费用),所以可以用 Mockito 来“骗”过业务逻辑。
首先项目代码中真实存在的快递下单服务:
java
public interface ExpressApi {
// 调用第三方接口获取运单号
String createOrder(String address, String phone);
}java
public class OrderManager {
private final ExpressApi expressApi;
public OrderManager(ExpressApi expressApi) {
this.expressApi = expressApi;
}
/**
* 下单
*/
public String placeOrder(String address, String phone) {
// 业务逻辑:校验手机号
if (phone == null || phone.length() < 11) {
return "INVALID_PHONE";
}
// 调用外部快递接口
String trackingNumber = expressApi.createOrder(address, phone);
return "ORDER_CREATED: " + trackingNumber;
}
}然后,在测试代码中我们就可以使用Mockito模拟快递下单动作:
java
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
@Test
void testPlaceOrder_Success() {
// 1. 创建替身 (Mock)
ExpressApi mockExpress = mock(ExpressApi.class);
OrderManager manager = new OrderManager(mockExpress);
// 2. 打桩 (Stubbing)
// 预设:只要调用接口,就返回假单号 "SF12345678"
when(mockExpress.createOrder(anyString(), anyString()))
.thenReturn("SF12345678");
// 执行被测业务
String result = manager.placeOrder("北京市朝阳区", "13800138000");
// 3. 验证 (Verify)
// 验证返回结果是否包含 Mock 的单号,JUnit提供的功能
assertEquals("ORDER_CREATED: SF12345678", result);
// 验证业务系统是否真的去调了快递接口(Mockito提供的功能)
verify(mockExpress).createOrder("北京市朝阳区", "13800138000");
}2.2 创建替身
在Mockito中,创建替身对象的方法主要在Mockito类中,主要分为两类:
- mock:
mock()创造的是一个完全的空壳; - spy:
spy()创造的是一个真实对象的包装层;
两者最重要的区别是:
如果没有对mock对象打桩,那么调用mock对象的任何方法,都不执行真实逻辑,默认返回 null, 0,false;
如果没有对spy对象打桩,那么调用spy对象的任何方法,都会默认执行真实逻辑。
mock()方法定义:
java
public static <T> T mock(Class<T> classToMock) {
// ...
}
public static <T> T mock(Class<T> classToMock, MockSettings mockSettings) {
// ...
}对于mock对象,只需要传入需要mock的类型,如果还有其他设置,可以通过MockSettings传入。
spy()方法定义:
java
public static <T> T spy(T object) {
// ...
}
public static <T> T spy(Class<T> classToSpy) {
// ...
}对于spy对象,有两种创建方式:
包装现有实例:这是最经典的用法。需要先
new一个真实对象,然后让 Mockito 给它套个“壳”。如果在new对象时通过构造函数传了参数,或者手动设置了属性,这些状态都会保留在spy对象中。凭空创建并调用构造函数:只需要传入需要spy对象的类型,然后默认调用该类的无参构造函数来实例化。如果该类没有无参构造函数,直接调用会报错:
org.mockito.exceptions.base.MockitoException: Unable to create mock instance of type 'XXX'
例如,下面的例子演示了mock与spy最重要的区别:
java
public class Calculator {
public int add(int a, int b) {
return a + b;
}
}java
public class CalculatorTest {
@Test
public void testAdd_spy() {
Calculator spy = spy(Calculator.class);
int result = spy.add(1, 2);
System.out.println(result);
// 结果为3
}
@Test
public void testAdd_mock() {
Calculator mock = mock(Calculator.class);
int result = mock.add(1, 2);
System.out.println(result);
// 结果为0
}
}2.3 打桩
打桩,解决“替身怎么表现”的问题,也就是说定义当调用替身对象的某个方法时,该方法应该执行什么逻辑、返回什么值。
在Mockito中,打桩主要分为两种风格:when(...).then... 风格(最常用)和 do...when(...) 风格(功能最全)。
TIP
注意,后打桩的会覆盖之前打桩的。
2.3.1 when(...).then... 风格
这是 Mockito 的标准语法,读起来就像英语句子:“当...的时候,然后...”。
返回固定值:
java
Calculator mock = mock(Calculator.class);
// 打桩
when(mock.add(1,2)).thenReturn(100);
int result = mock.add(1, 2); // result为100
int result2 = mock.add(1, 1); // result2为0,因为没有打桩第三行即打桩,表示当调用mock.add(1,2)时,返回100。注意参数也要匹配上,并且不会执行mock.add()内部逻辑。
假设Calculator.add()新加一行:
java
public class Calculator {
public int add(int a, int b) {
System.out.println("add...");
return a + b;
}
}是不会看到add...输出在控制台的。
抛出异常:
java
@Test
public void testAdd_mock_throw_exception(){
Calculator mock = mock(Calculator.class);
// 打桩,抛出异常
when(mock.add(1,1)).thenThrow(new RuntimeException("参数错误"));
Assertions.assertThrows(RuntimeException.class, () -> {
mock.add(1,1);
});
}连续触发不同结果:模拟同一个方法被多次调用时产生不同反应
java
@Test
public void testAdd_mock_multi_invokes() {
Calculator mock = mock(Calculator.class);
when(mock.add(1,2))
.thenReturn(1)
.thenReturn(2)
.thenThrow(new RuntimeException("参数错误"));
int result = mock.add(1, 2);
Assertions.assertEquals(1, result);
int result2 = mock.add(1, 2);
Assertions.assertEquals(2, result2);
RuntimeException runtimeException = Assertions.assertThrows(
RuntimeException.class,
() -> mock.add(1, 2)
);
Assertions.assertEquals("参数错误", runtimeException.getMessage());
}2.3.2 do...when(...) 风格
这种语法的顺序是反过来的。虽然读起来略显别扭,但在某些特定场景下,它是唯一的选择。
- 打桩 void 方法:
when(mock.voidMethod())在 Java 中无法编译,因为when需要一个返回值作为参数。 - 打桩 Spy 对象:为了避免执行真实的方法逻辑。
如果使用when...then风格打桩void方法:
java
public class Calculator {
public void sub(int a, int b) {
System.out.println("sub...");
System.out.println(a - b);
}
}java
Calculator mock = mock(Calculator.class);
when(mock.sub(2,1)).thenThrow(new RuntimeException("参数错误"));在编译期间就会报错。
使用do...when...风格修正如下:
java
@Test
void testSub_mock_return_void(){
Calculator mock = mock(Calculator.class);
doNothing().when(mock).sub(2,1);
mock.sub(2,1);
}如果在spy对象上使用when...then...风格打桩,那么会先触发调用一次真实逻辑,这次调用有很大的概率发生异常,造成测试失败。因此,对于spy对象,推荐使用do...when...方式打桩:
java
@Test
public void testAdd_spy() {
Calculator spy = spy(Calculator.class);
when(spy.add(1,2)).thenReturn(2); // 这里会输出 add...
int result = spy.add(1, 2);
System.out.println(result); // 这里会输出 2
}java
@Test
public void testAdd_spy_do_when() {
Calculator spy = spy(Calculator.class);
doReturn(2).when(spy).add(1,2); // 这里不会输出内容
int result = spy.add(1, 2);
System.out.println(result); // 输出 2
}2.3.3 参数匹配器
在上面的例子总,打桩时,我们都传入了具体的参数值,但实际上并不一定要传入精确的参数。Mockito 提供了强大的模糊匹配功能,在ArgumentMatchers类中,主要的有以下匹配器:
any():匹配任何参数;any(Class<T> type):匹配任何属于类型type的参数,不包括null;nullable(Class<T> clazz):匹配任何属于类型clazz的参数,包括null;anyBoolean()/anyInt()等:匹配原始类型;anyString():匹配任何字符串,不包括null;anyList()/anySet()/anyMap():匹配任何列表/集合/MAP;isNull()/notNull():匹配为null/不为null的参数;eq(T value):匹配等于value的参数;argThat(ArgumentMatcher<T> matcher):自定义满足匹配条件的参数,返回null,适用于类;javapublic static <T> T argThat(ArgumentMatcher<T> matcher) { reportMatcher(matcher); return null; }intThat(ArgumentMatcher<Integer> matcher):自定义满足匹配条件的整形,返回0;javapublic static int intThat(ArgumentMatcher<Integer> matcher) { reportMatcher(matcher); return 0; }
例如,下面的例子使用intThat(),匹配小于10的参数:
java
@Test
public void testAdd_spy_argThat() {
Calculator spy = spy(Calculator.class);
doReturn(2).when(spy).add(intThat(a -> a < 10), anyInt());
int result = spy.add(1, 2);
System.out.println(result); // 结果为 2,满足打桩条件
int result2 = spy.add(10, 2);
System.out.println(result2); // 结果为 12,不满足打桩条件,调用实际方法
}CAUTION
注意,如果其中一个参数使用了匹配器,其他参数也要使用,下面的例子会报错:
java
doReturn(2).when(spy).add(intThat(a -> a < 10), 2); org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
2 matchers expected, 1 recorded:
需要使用:
java
doReturn(2).when(spy).add(intThat(a -> a < 10), eq(2));2.3.4 定制化返回
如果不想返回写死的数据,也可以根据输入参数动态计算返回值,甚至还可以调用原始方法,使用thenAnswer(),例如:
java
@Test
public void testAdd_mock_thenAnswer(){
Calculator mock = mock(Calculator.class);
when(mock.add(anyInt(),anyInt())).thenAnswer(invocation -> {
Object argument1 = invocation.getArgument(0);
Integer argument2 = invocation.getArgument(1, Integer.class);
System.out.println(argument1 + " " + argument2);
Object realResult = invocation.callRealMethod();
System.out.println(realResult);
return realResult;
});
int result = mock.add(1, 1);
System.out.println(result);
}结果如下:
txt
1 1
add...
2
2invocation.getArgument():获取到调用参数;invocation.callRealMethod():调用真实方法,即使是在mock对象上,也能调用到真实方法;
如果mock的是接口,调用invocation.callRealMethod()时会报错:
org.mockito.exceptions.base.MockitoException:
Cannot call abstract real method on java object!
Calling real methods is only possible when mocking non abstract method.
2.4 验证
Mockito中的验证是指行为验证(Behavior Verification):确认某个 Mock 对象的某个方法,是否以预期的参数、预期的次数被调用了。主要使用verify()方法进行验证。
最基础的用法就是验证mock对象的某个方法是否以指定的参数被调用过:
java
Calculator spy = spy(Calculator.class);
doReturn(2).when(spy).add(intThat(a -> a < 10), eq(2));
int result = spy.add(1, 2);
Assertions.assertEquals(2,result);
// 验证
verify(spy).add(2,2);如果验证失败,整个测试方法会失败,显示如下信息:
Argument(s) are different! Wanted:
calculator.add(2, 2);
verify()默认验证方法是否调用了一次,还可以验证调用次数,精确控制逻辑触发的频率。
- 精确次数:
verify(mock, times(3)).method()(必须刚好 3 次) - 最少/最多:
atLeast(2)/atMost(5) - 从未调用:
never()(等同于times(0)) - 至少一次:
atLeastOnce()
java
// 验证调用了5次
verify(spy, times(5)).add(2,2);
// 验证从未被调用
verify(spy, never()).add(2,2);还可以验证调用的顺序:
java
Calculator mock = mock(Calculator.class);
doNothing().when(mock).sub(2,1);
doNothing().when(mock).sub(3,4);
mock.sub(2,1);
mock.sub(3,4);
InOrder inOrder = Mockito.inOrder(mock);
inOrder.verify(mock).sub(3,4);
inOrder.verify(mock).sub(2,1);
// 异常:
// org.mockito.exceptions.verification.VerificationInOrderFailure:
// Verification in order failure在方法参数上,我们可以使用参数匹配器:
java
verify(spy, times(5)).add(anyInt(), anyInt());如果参数比较复杂,我们可以使用参数捕获器,获取到实际调用的参数,根据参数来做判断:
java
@Test
public void testAdd_spy_captor() {
Calculator spy = spy(Calculator.class);
doReturn(2).when(spy).add(intThat(a -> a < 10), eq(2));
// 调用两次add
int result = spy.add(1, 2);
result = spy.add(1, 2);
Assertions.assertEquals(2,result);
// 定义一个参数捕获器
ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class);
// 验证,使用参数捕获器获取调用参数
verify(spy, atMost(5)).add(captor.capture(), captor.capture());
// 获取捕获到的参数,进行断言
// getValue 获取最后一个捕获到的参数
Integer value = captor.getValue();
System.out.println(value); // 结果为 2
List<Integer> allValues = captor.getAllValues();
System.out.println(allValues); // 结果为 [1, 2, 1, 2] ,因为调用了两次add
// 断言参数
Assertions.assertTrue(value < 10);
}3. 高级用法
3.1 @Mock、@Spy、@InjectMocks
在前面的例子(基本使用小节)中,我们使用mock()或spy()静态方法来创建测试替身,Mockito也提供了注解来创建测试替身:
@Mock:自动创建并注入mock对象;@Spy:自动创建并注入spy对象;@InjectMocks:自动为组建注入测试替身依赖;
注意,使用以上注解的前提是开启了相关配置,完整案例如下:
java
class OrderManagerTest {
private AutoCloseable autoCloseable;
// 创建测试替身,并注入到字段mockExpress
@Mock
private ExpressApi mockExpress;
// 将测试替身 mockExpress 注入到manager中
@InjectMocks
private OrderManager manager中;
// 开启配置
@BeforeEach
void setUp() {
autoCloseable = MockitoAnnotations.openMocks(this);
}
// 关闭配置
@AfterEach
void tearDown() throws Exception {
autoCloseable.close();
}
@Test
void testPlaceOrder_Success() {
// 创建测试替身已被注解替代
// 打桩 (Stubbing)
// 预设:只要调用接口,就返回假单号 "SF12345678"
when(mockExpress.createOrder(anyString(), anyString()))
.thenReturn("SF12345678");
// 执行被测业务
String result = manager.placeOrder("北京市朝阳区", "13800138000");
// 验证 (Verify)
// 验证返回结果是否包含 Mock 的单号,JUnit提供的功能
assertEquals("ORDER_CREATED: SF12345678", result);
// 验证业务系统是否真的去调了快递接口(Mockito提供的功能)
verify(mockExpress).createOrder("北京市朝阳区", "13800138000");
}
}以上开启配置和关闭配置可以有JUnit的扩展机制完成。
首先,引入依赖:
xml
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.22.0</version>
</dependency>然后使用MockitoExtension扩展插件:
java
@ExtendWith(MockitoExtension.class)
class OrderManagerTest {
private AutoCloseable autoCloseable;
@Mock
private ExpressApi mockExpress;
@InjectMocks
private OrderManager manager;
@Test
void testPlaceOrder_Success() {
// 创建测试替身已被注解替代
// 打桩 (Stubbing)
// 预设:只要调用接口,就返回假单号 "SF12345678"
when(mockExpress.createOrder(anyString(), anyString()))
.thenReturn("SF12345678");
// 执行被测业务
String result = manager.placeOrder("北京市朝阳区", "13800138000");
// 验证 (Verify)
// 验证返回结果是否包含 Mock 的单号,JUnit提供的功能
assertEquals("ORDER_CREATED: SF12345678", result);
// 验证业务系统是否真的去调了快递接口(Mockito提供的功能)
verify(mockExpress).createOrder("北京市朝阳区", "13800138000");
}
}3.2 @Captor
同样可以使用@Captor来定义参数捕获器:
java
@ExtendWith(MockitoExtension.class)
class OrderManagerTest {
private AutoCloseable autoCloseable;
@Mock
private ExpressApi mockExpress;
@InjectMocks
private OrderManager manager;
@Captor
private ArgumentCaptor<String> stringArgumentCaptor;
@Test
void testPlaceOrder_Success() {
// 创建测试替身已被注解替代
// 打桩 (Stubbing)
// 预设:只要调用接口,就返回假单号 "SF12345678"
when(mockExpress.createOrder(anyString(), anyString()))
.thenReturn("SF12345678");
// 执行被测业务
String result = manager.placeOrder("北京市朝阳区", "13800138000");
// 验证 (Verify)
// 验证返回结果是否包含 Mock 的单号,JUnit提供的功能
assertEquals("ORDER_CREATED: SF12345678", result);
// 验证业务系统是否真的去调了快递接口(Mockito提供的功能)
verify(mockExpress).createOrder(stringArgumentCaptor.capture(), stringArgumentCaptor.capture());
assertEquals("北京市朝阳区", stringArgumentCaptor.getAllValues().get(0));
assertEquals("13800138000", stringArgumentCaptor.getAllValues().get(1));
}
}3.3 MockSettings
MockSettings能在创建mock对象时,根据自身需要,定制化mock对象行为,在创建mock对象时传入:
java
mock(Class<T> classToMock, MockSettings mockSettings)通过 Mockito.withSettings()静态方法来创建MockSettings对象。
WARNING
注意,不要过多使用MockSettings,保持测试代码简单最重要。 如果在测试代码中过多使用了MockSettings,考虑重构代码。
常见的设置如下:
给mock对象取名字:
javamock(Calculator.class, withSettings().name("计算器"));额外实现接口:
javaCalculator calculator = mock(Calculator.class, withSettings().extraInterfaces(Serializable.class)); Assertions.assertTrue(calculator instanceof Serializable);启用序列化:默认的 Mock 对象是不可序列化的。如果业务逻辑会将mock对象存入 Redis ,不开启此项会抛出
NotSerializableException:javamock(Calculator.class, withSettings().serializable());定制mock方法的默认行为:通常 Mock 对象的方法返回
null或0。可以全局修改这个规则,比如让它默认调用真实方法,或者返回“聪明”的空值(RETURNS_SMART_NULLS):java// 设置mock对象调用真实方法 Calculator calculator = mock(Calculator.class, withSettings().defaultAnswer(Answers.CALLS_REAL_METHODS)); int add = calculator.add(1, 2); System.out.println(add);调用构造方法:当想 Mock 一个类但又想运行其构造函数里的逻辑时使用:
javamock(Calculator.class, withSettings().useConstructor());
3.4 重置测试替身
我们可以使用Mockito.reset(T... mocks)来重置mock对象,移除打的桩:
java
@Test
public void test() {
Calculator calculator = mock(Calculator.class);
doReturn(1).when(calculator).add(1,2);
// 重置mock对象
reset(calculator);
int add = calculator.add(1, 2);
System.out.println(add); // 结果为 0
}3.5 mockStatic()
Mockito支持对静态方法进行打桩,例如:
java
public class StaticUtils {
public static String getUrl()
{
return "http://xxx:80";
}
}java
@Test
public void test2() {
// mock静态方法
try (MockedStatic<StaticUtils> utilities = mockStatic(StaticUtils.class)) {
utilities.when(StaticUtils::getUrl).thenReturn("http://localhost:8080");
assertEquals("http://localhost:8080", StaticUtils.getUrl());
}
// 退出 try 块后,StaticUtils 恢复正常行为
assertEquals("http://xxx:80", StaticUtils.getUrl());
}3.6 BDD
BDD,全称Behavior-Driven Development,是指按照 // Given // When // Then 风格来编写测试代码的开发方式,例如:
java
@Test
public void test(){
// Given
// When
// Then
}- Given:主要就是打桩
- When:在mock/spy对象上调用方法
- Then:验证
例如:
java
Seller seller = mock(Seller.class);
Shop shop = new Shop(seller);
public void shouldBuyBread() throws Exception {
//given
doReturn(new Bread()).when(seller).askForBread();
//when
Goods goods = shop.buyBread();
//then
assertThat(goods, containBread());
}在第8行中,打桩我们使用了when(),但这属于// Given 板块,容易造成歧义,因此,Mockito提出了BDDMockito类,用来替代when()方法,如下:
java
BDDMockito.willReturn(new Bread()).given(seller).askForBread();
// 或者
BDDMockito.given(seller.askForBread()).willReturn(new Bread());对于BDD风格的验证方法,也提出了then()方法,如下:
java
person.ride(bike);
person.ride(bike);
then(person).should(times(2)).ride(bike);
then(person).shouldHaveNoMoreInteractions();
then(police).shouldHaveZeroInteractions();4. Mockito的限制
Mockito不支持对私有方法(private)的打桩。
这是 Mockito 团队的一种设计哲学。
- 原因:Mockito 认为私有方法是类的内部实现细节。如果必须 Mock 私有方法才能进行测试,通常意味着类职责过重,应该重构(例如将私有逻辑抽离到另一个类的 public 方法中)。
- 替代方案:如果非要 Mock,可以使用反射工具类,或者使用 PowerMock(但不推荐,因为 PowerMock 维护状态不佳且不支持 JUnit 5)。
Mockito也不支持hashCode() 和 equals() 方法打桩。
- 原因:Mockito 的内部集合和对象跟踪机制严重依赖这些方法。如果修改了它们的行为,Mockito 可能无法识别它自己创建的 Mock 对象,导致验证(verify)失效。
- 替代方案:如果需要对象相等性逻辑,需要测试中创建真实的 DTO 对象,或者使用
ArgumentMatchers.argThat来进行自定义属性比对。
参考资料
[1] Mockito官方网站:https://site.mockito.org/
[2] https://javadoc.io/doc/org.mockito/mockito-core/latest/org.mockito/org/mockito/InjectMocks.html
[3] https://dzone.com/refcardz/mockito
[4] 官方教程:https://javadoc.io/doc/org.mockito/mockito-core/latest/org.mockito/org/mockito/Mockito.html