Mockito 快速入门教程
-
概述
Mockito 是一个流行的Java单元测试Mock框架,用于接口和数据模拟。 -
依赖安装
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.12.4</version>
<scope>test</scope>
</dependency>
// 静态导入会使代码更简洁
import static org.mockito.Mockito.*;
// mock creation 创建mock对象
List mockedList = mock(List.class);
//using mock object 使用mock对象
mockedList.add("one");
mockedList.clear();
//verification 验证
verify(mockedList).add("one");
verify(mockedList).clear();
一旦mock对象被创建了,mock对象会记住所有的交互。然后你就可能选择性的验证你感兴趣的交互。
如何做一些测试桩 (Stub)?
//You can mock concrete classes, not only interfaces
// 你可以mock具体的类型,不仅只是接口
LinkedList mockedList = mock(LinkedList.class);
//stubbing
// 测试桩
when(mockedList.get(0)).thenReturn("first");
when(mockedList.get(1)).thenThrow(new RuntimeException());
//following prints "first"
// 输出“first”
System.out.println(mockedList.get(0));
//following throws runtime exception
// 抛出异常
System.out.println(mockedList.get(1));
//following prints "null" because get(999) was not stubbed
// 因为get(999) 没有打桩,因此输出null
System.out.println(mockedList.get(999));
//Although it is possible to verify a stubbed invocation, usually it's just redundant
//If your code cares what get(0) returns then something else breaks (often before even verify() gets executed).
//If your code doesn't care what get(0) returns then it should not be stubbed. Not convinced? See here.
// 验证get(0)被调用的次数
verify(mockedList).get(0);
默认情况下,所有的函数都有返回值。mock函数默认返回的是null,一个空的集合或者一个被对象类型包装的内置类型,例如0、false对应的对象类型为Integer、Boolean;
测试桩函数可以被覆写 : 例如常见的测试桩函数可以用于初始化夹具,但是测试函数能够覆写它。请注意,覆写测试桩函数是一种可能存在潜在问题的做法;
一旦测试桩函数被调用,该函数将会一致返回固定的值;
上一次调用测试桩函数有时候极为重要-当你调用一个函数很多次时,最后一次调用可能是你所感兴趣的。
import static org.mockito.Mockito.*;
// 创建mock对象
// 你可以mock具体的类型,不仅只是接口
List mockedList = mock(List.class);
// 对于高版本Mockito 4.10.0+,可以写的更简洁
// List mockedList = mock();
// 下面添加测试桩(stubbing),指定mock的行为
// ”当“ 调用 mockedList.get(0) 返回 "first"
when(mockedList.get(0)).thenReturn("first");
// 下面代码将打印 "first"
System.out.println(mockedList.get(0));
// 下面将打印 "null",因为 get(999) 没有被打桩
System.out.println(mockedList.get(999));
上面示例,首先我们使用 Mockito 中的 mock 静态方法创建mock对象。或使用 @Mock 注解,通过 when()/given() 指定mock行为。例如上面当调用 mockedList.get(0) 将返回 “first”,这一过程专业术语叫做“打桩”(stubbing)。
除了 mock()/@Mock,还可使用 spy()/@Spy,两者区别是 spy 是部分mock,如果不打桩执行的是真实的方法。
使用 @InjectMocks 注解实现依赖注入,自动将mock/spy对象注入到被测试对象中。
Mockito 中的 @Mock, @Spy, @Captor 及 @InjectMocks 注解
开始之前,我们需要先使 Mockito 注解生效,有几种方法:
方法一:在JUnit 上设置 MockitoJUnitRunner
@ExtendWith(MockitoExtension.class)
public class MockitoAnnotationUnitTest {
...
}
方法二:手动编码,调用 MockitoAnnotations.openMocks() 方法
@Before
public void init() {
MockitoAnnotations.openMocks(this);
}
最后, 我们可以使用 MockitoJUnit.rule():
public class MockitoAnnotationsInitWithMockitoJUnitRuleUnitTest {
@Rule
public MockitoRule initRule = MockitoJUnit.rule();
...
}
注意,这需要将rule 设置为 public
@Mock 注解
@Mock 是 Mockito 中用的最多的注解,我们用它来创建并注入mock对象,而不用手动调用 Mockito.mock 方法。
为了方便对比,下面这个例子中,我们先是手动mock一个ArrayList
@Test
public void whenNotUseMockAnnotation_thenCorrect() {
List mockList = Mockito.mock(ArrayList.class);
mockList.add("one");
Mockito.verify(mockList).add("one");
assertEquals(0, mockList.size());