一、Mockito简介
在单元测试开发中,经常会遇到测试的类中有很多依赖的类、对象、资源,从而形成巨大的依赖树,mock可以模拟外部依赖,适应单元测试。
比如在开发中很容易出现这种情况:
(a)依赖(b)依赖(c)依赖(d)
这种情况下单元测试就变得极其复杂,比如需要数据库或网络请求返回值的情况。
因此需要引入Mockito让单元测试变得简单,可以通过mock虚拟外部依赖,并可以通过打桩操作轻松地修改返回值甚至抛出异常:
(a)依赖(mock b)
二、Mockito环境设置
在应用Mockito之前需要在build.gradle文件中添加相应的依赖:
三、Mockito的使用
Mockito的使用步骤 |
① 创建mock对象,并对mock对象进行打桩设置返回值; ② 创建被测试类,并调用测试的方法; ③ 对真实值和期盼值进行assert验证。 |
1、简单使用示例
要测试的类:
public class BusinessServiceImpl implements BusinessService { private DataAccessService das; @Override public void setDataAccessService(DataAccessService das) { this.das = das; } // 被测试方法,依赖 DataAccessService @Override public List<String> queryAllUsers() { return das.queryAllUsers(); } } |
可见,queryAllUsers()方法的测试依赖DataAccessService的具体实现,我们可以选择mock这个对象并进行打桩指定返回值。
import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.Mockito; class BusinessServiceTest { @Test void testQueryAllUsers() { List<String> expectedAllUsers = Arrays.asList("test1", "test2"); // 创建依赖对象并打桩设置返回值 DataAccessService das = Mockito.mock(DataAccessService.class); Mockito.when(das.queryAllUsers()).thenReturn(expectedAllUsers); // 创建测试对象 BusinessService businessService = new BusinessServiceImpl(); businessService.setDataAccessService(das); // 调用测试方法 List<String> actual = businessService.queryAllUsers(); // 比较测试结果 Assertions.assertEquals(expectedAllUsers, actual); } } |
2、Mockito使用spy
spy允许我们部分mock一个类,即只对类中的一些方法打桩设置返回值,其他方法调用仍旧是正常调用。
示例 |
import java.util.ArrayList; import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.Mockito; class SpyTest { @Test void test() { // spy 允许我们部分 mock 一个类 List<String> data = Mockito.spy(new ArrayList<>()); // stubbing size 方法,即对size方法进行打桩 Mockito.doReturn(10).when(data).size(); // 调用真实的方法 data.add("a"); // 验证 Assertions.assertEquals("a", data.get(0)); Assertions.assertEquals(10, data.size()); } } |
3、Mockito匹配参数
匹配任意参数的意思是,针对该方法输入任何参数,都返回打桩的值。
示例 |
import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatchers; import org.mockito.Mockito; class ArgumentMatchersTest { @Test void test() { // mock creation List<String> data = Mockito.mock(List.class); // stubbing, 匹配任何 int 参数 Mockito.when(data.get(ArgumentMatchers.anyInt())).thenReturn("test"); // verification Assertions.assertEquals("test", data.get(0)); Assertions.assertEquals("test", data.get(10)); } } |
4、Mockito多次调用返回不同值
多次调用返回不同值即对该mock对象多次调用测试方法,设置它返回不同的值。
示例 |
import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.Mockito; class DifferentRtnForSameMethodCallTest { @Test void test() { // mock creation List<String> data = Mockito.mock(List.class); // stubbing // 第一次调用返回 10 // 第一次调用返回 20 Mockito.when(data.size()).thenReturn(10, 20); // verification Assertions.assertEquals(10, data.size()); Assertions.assertEquals(20, data.size()); } } |
5、Mockito Stub void方法
对返回值为空的方法进行打桩,就意味着mock对象在调用这个方法时并不执行方法要实现的功能,即什么都不干。
示例 |
import java.util.ArrayList; import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.Mockito; class VoidMethodTest { @Test void test() { // mock creation List<String> data = Mockito.spy(new ArrayList<>()); data.add("a"); // stubbing void method Mockito.doNothing().when(data).clear(); // verification data.clear(); // 意味着并没有执行clear操作,“a”仍旧存在于列表中 Assertions.assertEquals(1, data.size()); } } |