Mockito 小结
为什么要使用Mock
进行测试
- 传统测试,后端工程师依赖一些第三方的接口(支付、定时任务等不方便真实测试的接口),前端工程师依赖后端的接口,测试工程师依赖前端的接口
- 使用
Mock
,使用虚拟对象进行测试,达到解耦、并行开发。 - 使用
Mock
,搭配测试工具,可以发现未被测试覆盖的代码,提高代码的健壮性。
常见的mock
框架
Mockito
的常用API
- 添加
Mockito
依赖 和Junit
依赖
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.8.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
- 生成 mock(模拟)对象 (多种方式)
若无特殊说明,所有的地方均静态导入了这个包
import static org.mockito.Mockito.*;
直接创建mock对象
//create mock
List mockedList = mock(List.class);
通过注解注入mock对象
@RunWith(MockitoJUnitRunner.class)
public class Test {
@Mock
private AMapper aMapper;
@InjectMock
private AService AServiceImpl;
@Test
public void test() {
when(aMapper.add()).thenReturn(1);
int code = aService.add();
Assert.isTrue(code == 1, "添加失败");
}
interface AService {
public int add();
}
@Service
class AServiceImpl implements AService {
@Autowired
private AMapper aMapper;
@Override
public int add() {
return aMapper.insert(new Object());
}
}
}
拓展,创建spy对象
List mockList= mock(List.class);
List spy = spy(mockList);
- 使用mock对象
测试桩(Stub)模式:默认情况,一个mock对象的函数返回为null或基础类型的默认值。测试桩函数会覆盖函数返回值。
一个简单的例子
// 创建 mock 对象
List mockedList = mock(List.class);
// 测试桩
when(mockedList.get(0)).thenReturn("first");
// 连续测试桩
when(mockedList.get(1)).thenReturn("once").thenReturn("twice");
// 异常测试桩
when(mockedList.get(2)).thenThrow(new RuntimeException());
// 打印 first
System.out.println(mockedList.get(0));
// 打印 once
System.out.println(mockedList.get(1));
// 打印 twice
System.out.println(mockedList.get(1));
// 打印 null
System.out.println(mockedList.get(999));
// 报 RuntimeException 异常
System.out.println(mockedList.get(2));
使用 anyXXX()
// 创建 mock 对象
List mockedList = mock(List.class);
when(mockedList.get(anyInt())).thenReturn("element");
//打印 element
System.out.println(mockedList.get(999));
verify(mockedList).get(anyInt());
次数验证
// 创建 mock 对象
List mockedList = mock(List.class);
mockedList.add("once");
mockedList.add("twice");
mockedList.add("twice");
mockedList.add("three times");
mockedList.add("three times");
mockedList.add("three times");
// 1次 once
verify(mockedList, times(1)).add("once");
// 2次 twice
verify(mockedList, times(2)).add("twice");
// 3次 three times
verify(mockedList, times(3)).add("three times");
// 一次都不存在 never happened
verify(mockedList, never()).add("never happened");
// 拓展
// 最少一次 three times
verify(mockedList, atLeastOnce()).add("three times");
// 最少两次 five times
// verify(mockedList, atLeast(2)).add("five times");
// 最多5次 three times
// verify(mockedList, atMost(5)).add("three times");
顺序验证
// 创建 mock 对象, 进行单个对象的顺序验证
List singleMock = mock(List.class);
singleMock.add("was added first");
singleMock.add("was added second");
InOrder inOrder = inOrder(singleMock);
inOrder.verify(singleMock).add("was added first");
inOrder.verify(singleMock).add("was added second");
// 创建多个 mock 对象,进行多个mock对象的顺序验证
List firstList = mock(List.class);
List secondList = mock(List.class);
firstList.add("was added first");
secondList.add("was added second");
InOrder order = inOrder(firstList, secondList);
order.verify(firstList).add("was added first");
order.verify(secondList).add("was added second");