作者:京东零售 秦浩然

一、前期准备~

1、准备工作

<!--mockito依靠-->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>2.7.19</version>
    <scope>test</scope>
</dependency>
<!-- junit依靠 -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

2、入门常识

1)Mockito:简略轻量级的做mocking测验的结构;
2)mock目标:在调试期间用来作为实在目标的替代品;
3)mock测验:在测验过程中,对那些不容易构建的目标用一个虚拟目标来替代测验的办法就叫mock测验;
4)stub:打桩,便是为mock目标的办法指定回来值(可抛出反常);
5)verify:行为验证,验证指定办法调用状况(是否被调用,调用次数等);

3、五分钟入门Demo

@Test
public void test0() {
    //1、创立mock目标(模仿依靠的目标)
    final List mock = Mockito.mock(List.class);
    //2、运用mock目标(mock目标会对接口或类的办法给出默许完结)
    System.out.println("mock.add result => " + mock.add("first"));  //false
    System.out.println("mock.size result => " + mock.size());       //0
    //3、打桩操作(状态测验:设置该目标指定办法被调用时的回来值)
    Mockito.when(mock.get(0)).thenReturn("second");
    Mockito.doReturn(66).when(mock).size();
    //3、运用mock目标的stub(测验打桩成果)
    System.out.println("mock.get result => " + mock.get(0));    //second
    System.out.println("mock.size result => " + mock.size());   //66
    //4、验证交互 verification(行为测验:验证办法调用状况)
    Mockito.verify(mock).get(Mockito.anyInt());
    Mockito.verify(mock, Mockito.times(2)).size();
    //5、验证回来的成果(这是JUnit的功用)
    assertEquals("second", mock.get(0));
    assertEquals(66, mock.size());
}

二、让咱们开始学习吧!

1、行为验证

• 一旦mock目标被创立了,mock目标会记住一切的交互,然后你就能够选择性的验证你感兴趣的交互,验证不经过则抛出反常。

@Test
public void test1() {
    final List mockList = Mockito.mock(List.class);
    mockList.add("mock1");
    mockList.get(0);
    mockList.size();
    mockList.clear();
    // 验证办法被运用(默许1次)
    Mockito.verify(mockList).add("mock1");
    // 验证办法被运用1次
    Mockito.verify(mockList, Mockito.times(1)).get(0);
    // 验证办法至少被运用1次
    Mockito.verify(mockList, Mockito.atLeast(1)).size();
    // 验证办法没有被运用
    Mockito.verify(mockList, Mockito.never()).contains("mock2");
    // 验证办法至多被运用5次
    Mockito.verify(mockList, Mockito.atMost(5)).clear();
    // 指定办法调用超时时间
    Mockito.verify(mockList, timeout(100)).get(0);
    // 指定时间内需求完结的次数
    Mockito.verify(mockList, timeout(200).atLeastOnce()).size();
}

2、如何做一些测验桩stub

• 默许状况下,一切的函数都有回来值。mock函数默许回来的是null,一个空的集合或许一个被目标类型包装的内置类型,例如0、false对应的目标类型为Integer、Boolean;

• 一旦测验桩函数被调用,该函数将会共同回来固定的值;

• 关于 static 和 final 办法, Mockito 无法对其 when(…).thenReturn(…) 操作。

@Test
public void test2() {
    //静态导入,削减代码量:import static org.mockito.Mockito.*;
    final ArrayList mockList = mock(ArrayList.class);
    // 设置办法调用回来值
    when(mockList.add("test2")).thenReturn(true);
    doReturn(true).when(mockList).add("test2");
    System.out.println(mockList.add("test2"));  //true
    // 设置办法调用抛出反常
    when(mockList.get(0)).thenThrow(new RuntimeException());
    doThrow(new RuntimeException()).when(mockList).get(0);
    System.out.println(mockList.get(0));    //throw RuntimeException
    // 无回来办法打桩
    doNothing().when(mockList).clear();
    // 为回调做测验桩(对办法回来进行阻拦处理)
    final Answer<String> answer = new Answer<String>() {
        @Override
        public String answer(InvocationOnMock invocationOnMock) throws Throwable {
            final List mock = (List) invocationOnMock.getMock();
            return "mock.size result => " + mock.size();
        }
    };
    when(mockList.get(1)).thenAnswer(answer);
    doAnswer(answer).when(mockList).get(1);
    System.out.println(mockList.get(1));    //mock.size result => 0
    // 对同一办法屡次打桩,以最终一次为准
    when(mockList.get(2)).thenReturn("test2_1");
    when(mockList.get(2)).thenReturn("test2_2");
    System.out.println(mockList.get(2));    //test2_2
    System.out.println(mockList.get(2));    //test2_2
    // 设置屡次调用同类型成果
    when(mockList.get(3)).thenReturn("test2_1", "test2_2");
    when(mockList.get(3)).thenReturn("test2_1").thenReturn("test2_2");
    System.out.println(mockList.get(3));    //test2_1
    System.out.println(mockList.get(3));    //test2_2
    // 为连续调用做测验桩(为同一个函数调用的不同的回来值或反常做测验桩)
    when(mockList.get(4)).thenReturn("test2").thenThrow(new RuntimeException());
    doReturn("test2").doThrow(new RuntimeException()).when(mockList).get(4);
    System.out.println(mockList.get(4));    //test2
    System.out.println(mockList.get(4));    //throw RuntimeException
    // 无打桩办法,回来默许值
    System.out.println(mockList.get(99));    //null
}

3、参数匹配器

• 参数匹配器使验证和测验桩变得更灵敏;

• 为了合理的运用杂乱的参数匹配,运用equals()与anyX() 的匹配器会使得测验代码更简洁、简略。有时,会迫使你重构代码以运用equals()匹配或许完结equals()函数来协助你进行测验;

• 假如你运用参数匹配器,一切参数都必须由匹配器供给;

• 支撑自定义参数匹配器;

@Test
public void test3() {
    final Map mockMap = mock(Map.class);
    // 正常打桩测验
    when(mockMap.get("key")).thenReturn("value1");
    System.out.println(mockMap.get("key"));     //value1
    // 为灵敏起见,可运用参数匹配器
    when(mockMap.get(anyString())).thenReturn("value2");
    System.out.println(mockMap.get(anyString()));   //value2
    System.out.println(mockMap.get("test_key"));    //value2
    System.out.println(mockMap.get(0)); //null
    // 多个入参时,要么都运用参数匹配器,要么都不运用,否则会反常
    when(mockMap.put(anyString(), anyInt())).thenReturn("value3");
    System.out.println(mockMap.put("key3", 3));     //value3
    System.out.println(mockMap.put(anyString(), anyInt()));     //value3
    System.out.println(mockMap.put("key3", anyInt()));    //反常
    // 行为验证时,也支撑运用参数匹配器
    verify(mockMap, atLeastOnce()).get(anyString());
    verify(mockMap).put(anyString(), eq(3));
    // 自定义参数匹配器
    final ArgumentMatcher<ArgumentTestRequest> myArgumentMatcher = new ArgumentMatcher<ArgumentTestRequest>() {
        @Override
        public boolean matches(ArgumentTestRequest request) {
            return "name".equals(request.getName()) || "value".equals(request.getValue());
        }
    };
    // 自定义参数匹配器运用
    final ArgumentTestService mock = mock(ArgumentTestService.class);
    when(mock.argumentTestMethod(argThat(myArgumentMatcher))).thenReturn("success");
    doReturn("success").when(mock).argumentTestMethod(argThat(myArgumentMatcher));
    System.out.println(mock.argumentTestMethod(new ArgumentTestRequest("name", "value")));  // success
    System.out.println(mock.argumentTestMethod(new ArgumentTestRequest()));     //null
}

4、履行次序验证

• 验证履行次序是非常灵敏的-你不需求一个一个的验证一切交互,只需求验证你感兴趣的目标即可;

• 你能够仅经过那些需求验证次序的mock目标来创立InOrder目标;

@Test
public void test4() {
    // 验证同一个目标多个办法的履行次序
    final List mockList = mock(List.class);
    mockList.add("first");
    mockList.add("second");
    final InOrder inOrder = inOrder(mockList);
    inOrder.verify(mockList).add("first");
    inOrder.verify(mockList).add("second");
    // 验证多个目标多个办法的履行次序
    final List mockList1 = mock(List.class);
    final List mockList2 = mock(List.class);
    mockList1.get(0);
    mockList1.get(1);
    mockList2.get(0);
    mockList1.get(2);
    mockList2.get(1);
    final InOrder inOrder1 = inOrder(mockList1, mockList2);
    inOrder1.verify(mockList1).get(0);
    inOrder1.verify(mockList1).get(2);
    inOrder1.verify(mockList2).get(1);
}

5、确保交互(interaction)操作不会履行在mock目标上

• 一些用户或许会在频繁地运用verifyNoMoreInteractions(),甚至在每个测验函数中都用。可是verifyNoMoreInteractions()并不主张在每个测验函数中都运用;

• verifyNoMoreInteractions()在交互测验套件中只是一个便利的验证,它的作用是当你需求验证是否存在冗余调用时;

@Test
public void test5() {
    // 验证某个交互是否从未被履行
    final List mock = mock(List.class);
    mock.add("first");
    verify(mock, never()).add("test5");   //经过
    verify(mock, never()).add("first");  //反常
    // 验证mock目标没有交互过
    final List mock1 = mock(List.class);
    final List mock2 = mock(List.class);
    verifyZeroInteractions(mock1);  //经过
    verifyNoMoreInteractions(mock1, mock2); //经过
    verifyZeroInteractions(mock, mock2);  //反常
    // 留意:或许只想验证前面的逻辑,可是加上最终一行,会导致出现反常。主张运用办法层面的验证,如:never();
    //      在验证是否有冗余调用的时候,可运用此种方式。如下:
    final List mockList = mock(List.class);
    mockList.add("one");
    mockList.add("two");
    verify(mockList).add("one");    // 经过
    verify(mockList, never()).get(0);    //经过
    verifyZeroInteractions(mockList);   //反常
}

6、运用注解简化mock目标创立

留意!下面这句代码需求在运转测验函数之前被调用,一般放到测验类的基类或许test runner中:

MockitoAnnotations.initMocks(this);

也能够运用内置的runner: MockitoJUnitRunner 或许一个rule : MockitoRule;

// 替代 mock(ArgumentTestService.class) 创立mock目标;
@Mock
private ArgumentTestService argumentTestService;
// 若改注解润饰的目标有成员变量,@Mock定义的mock目标会被主动注入;
@InjectMocks
private MockitoAnnotationServiceImpl mockitoAnnotationService;
@Test
public void test6() {
    // 留意!下面这句代码需求在运转测验函数之前被调用,一般放到测验类的基类或许test runner中;
    MockitoAnnotations.initMocks(this);
    when(argumentTestService.argumentTestMethod(new ArgumentTestRequest())).thenReturn("success");
    System.out.println(argumentTestService.argumentTestMethod(new ArgumentTestRequest()));  //success
    System.out.println(mockitoAnnotationService.mockitoAnnotationTestMethod()); //null
}

7、监控实在目标(部分mock)

• 能够为实在目标创立一个监控(spy)目标。当你运用这个spy目标时实在的目标也会也调用,除非它的函数被stub了;

• 尽量少运用spy目标,运用时也需求小心形式,例如spy目标能够用来处理留传代码;

• stub语法中相同供给了部分mock的办法,能够调用实在的办法;

彻底mock:

上文讲的内容是彻底mock,即创立的mock目标与实在目标无关,mock目标的办法默许都是根本的完结,回来根本类型。可基于接口、完结类创立mock目标。

部分mock:

所谓部分mock,即创立的mock目标时基于实在目标的,mock目标的办法都是默许运用实在目标的办法,除非stub之后,才会以stub为准。基于完结类创立mock目标,否则在没有stub的状况下,调用实在办法时,会出现反常。

留意点:

Mockito并不会为实在目标代理函数调用,实际上它会拷贝实在目标。因此假如你保留了实在目标并且与之交互,不要期望从监控目标得到正确的成果。 当你在监控目标上调用一个没有被stub的函数时并不会调用实在目标的对应函数,你不会在实在目标上看到任何效果

@Test
public void test7() {
    // stub部分mock(stub中运用实在调用)。留意:需求mock完结类,否则会有反常
    final StubTestService stubTestService = mock(StubTestServiceImpl.class);
    when(stubTestService.stubTestMethodA("paramA")).thenCallRealMethod();
    doCallRealMethod().when(stubTestService).stubTestMethodB();
    System.out.println(stubTestService.stubTestMethodA("paramA"));  //stubTestMethodA is called, param = paramA
    System.out.println(stubTestService.stubTestMethodB());  //stubTestMethodB is called
    System.out.println(stubTestService.stubTestMethodC());  //null
    // spy部分mock
    final LinkedList<String> linkedList = new LinkedList();
    final LinkedList spy = spy(linkedList);
    spy.add("one");
    spy.add("two");
    doReturn(100).when(spy).size();
    when(spy.get(0)).thenReturn("one_test");
    System.out.println(spy.size()); //100
    System.out.println(spy.get(0)); //one_test
    System.out.println(spy.get(1)); //two
    // spy能够类比AOP。在spy中,因为默许是调用实在办法,所以第二种写法不等价于第一种写法,不引荐这种写法。
    doReturn("two_test").when(spy).get(2);
    when(spy.get(2)).thenReturn("two_test"); //反常 java.lang.IndexOutOfBoundsException: Index: 2, Size: 2
    System.out.println(spy.get(2));   //two_test
    // spy目标只是实在目标的复制,实在目标的改动不会影响spy目标
    final List<String> arrayList = new ArrayList<>();
    final List<String> spy1 = spy(arrayList);
    spy1.add(0, "one");
    System.out.println(spy1.get(0));    //one
    arrayList.add(0, "list1");
    System.out.println(arrayList.get(0));   //list1
    System.out.println(spy1.get(0));    //one
    // 若对某个办法stub之后,又想调用实在的办法,能够运用reset(spy)
    final ArrayList<String> arrayList1 = new ArrayList<>();
    final ArrayList<String> spy2 = spy(arrayList1);
    doReturn(100).when(spy2).size();
    System.out.println(spy2.size());    //100
    reset(spy2);
    System.out.println(spy2.size());    //0
}

8、@Mock 和 @Spy的运用

• @Mock 等价于 Mockito.mock(Object.class);

• @Spy 等价于 Mockito.spy(obj);

区别是mock目标还是spy目标:
Mockito.mockingDetails(someObject).isMock();
Mockito.mockingDetails(someObject).isSpy();
@Mock
private StubTestService stubTestService;
@Spy
private StubTestServiceImpl stubTestServiceImpl;
@Spy
private StubTestService stubTestServiceImpl1 = new StubTestServiceImpl();
@Test
public void test8() {
    MockitoAnnotations.initMocks(this);
    // mock目标回来默许
    System.out.println(stubTestService.stubTestMethodB());  //null
    // spy目标调用实在办法
    System.out.println(stubTestServiceImpl.stubTestMethodC());  //stubTestMethodC is called
    System.out.println(stubTestServiceImpl1.stubTestMethodA("spy"));  //stubTestMethodA is called, param = spy
    // 区别是mock目标还是spy目标
    System.out.println(mockingDetails(stubTestService).isMock());   //true
    System.out.println(mockingDetails(stubTestService).isSpy());    //false
    System.out.println(mockingDetails(stubTestServiceImpl).isSpy());    //true
}

9、ArgumentCaptor(参数捕获器)捕获办法参数进行验证。(可替代参数匹配器运用)

• 在某些场景中,不但要对办法的回来值和调用进行验证,一起需求验证一系列交互后所传入办法的参数。那么咱们能够用参数捕获器来捕获传入办法的参数进行验证,看它是否契合咱们的要求。

ArgumentCaptor介绍

经过ArgumentCaptor目标的forClass(Class

ArgumentCaptor的Api

argument.capture() 捕获办法参数

argument.getValue() 获取办法参数值,假如办法进行了屡次调用,它将回来最终一个参数值

argument.getAllValues() 办法进行屡次调用后,回来多个参数值

@Test
public void test9() {
    List mock = mock(List.class);
    List mock1 = mock(List.class);
    mock.add("John");
    mock1.add("Brian");
    mock1.add("Jim");
    // 获取办法参数
    ArgumentCaptor argument = ArgumentCaptor.forClass(String.class);
    verify(mock).add(argument.capture());
    System.out.println(argument.getValue());    //John
    // 屡次调用获取最终一次
    ArgumentCaptor argument1 = ArgumentCaptor.forClass(String.class);
    verify(mock1, times(2)).add(argument1.capture());
    System.out.println(argument1.getValue());    //Jim
    // 获取一切调用参数
    System.out.println(argument1.getAllValues());    //[Brian, Jim]
}

10、简化 ArgumentCaptor 的创立

@Mock
private List<String> captorList;
@Captor
private ArgumentCaptor<String> argumentCaptor;
@Test
public void test10() {
    MockitoAnnotations.initMocks(this);
    captorList.add("cap1");
    captorList.add("cap2");
    System.out.println(captorList.size());
    verify(captorList, atLeastOnce()).add(argumentCaptor.capture());
    System.out.println(argumentCaptor.getAllValues());
}

11、高档特性:自定义验证失利信息

@Test
public void test11() {
    final ArrayList arrayList = mock(ArrayList.class);
    arrayList.add("one");
    arrayList.add("two");
    verify(arrayList, description("size()没有调用")).size();
    // org.mockito.exceptions.base.MockitoAssertionError: size()没有调用
    verify(arrayList, timeout(200).times(3).description("验证失利")).add(anyString());
    //org.mockito.exceptions.base.MockitoAssertionError: 验证失利
}

12、高档特性:修改没有测验桩的调用的默许回来值

• 能够指定策略来创立mock目标的回来值。这是一个高档特性,一般来说,你不需求写这样的测验;

• 它关于留传体系来说是很有用处的。当你不需求为函数调用打桩时你能够指定一个默许的answer;

@Test
public void test12(){
    // 创立mock目标、运用默许回来
    final ArrayList mockList = mock(ArrayList.class);
    System.out.println(mockList.get(0));    //null
    // 这个完结首要测验大局装备,假如没有大局装备就会运用默许的答复,它回来0,空集合,null,等等。
    // 参阅回来装备:ReturnsEmptyValues
    mock(ArrayList.class, Answers.RETURNS_DEFAULTS);
    // ReturnsSmartNulls首要测验回来普通值(0,空集合,空字符串,等等)然后它企图回来SmartNull。
    // 假如最终回来目标,那么会简略回来null。一般用在处理留传代码。
    // 参阅回来装备:ReturnsMoreEmptyValues
    mock(ArrayList.class, Answers.RETURNS_SMART_NULLS);
    // 未stub的办法,会调用实在办法。
    //    注1:存根部分模仿运用时(mock.getSomething ()) .thenReturn (fakeValue)语法将调用的办法。关于部分模仿引荐运用doReturn语法。
    //    注2:假如模仿是序列化反序列化,那么这个Answer将无法理解泛型的元数据。
    mock(ArrayList.class, Answers.CALLS_REAL_METHODS);
    // 深度stub,用于嵌套目标的mock。参阅:https://www.cnblogs.com/Ming8006/p/6297333.html
    mock(ArrayList.class, Answers.RETURNS_DEEP_STUBS);
    // ReturnsMocks首要测验回来普通值(0,空集合,空字符串,等等)然后它企图回来mock。
    // 假如回来类型不能mocked(例如是final)然后回来null。
    mock(ArrayList.class, Answers.RETURNS_MOCKS);
    //  mock目标的办法调用后,能够回来自己(类似builder模式)
    mock(ArrayList.class, Answers.RETURNS_SELF);
    // 自定义回来
    final Answer<String> answer = new Answer<String>() {
        @Override
        public String answer(InvocationOnMock invocation) throws Throwable {
            return "test_answer";
        }
    };
    final ArrayList mockList1 = mock(ArrayList.class, answer);
    System.out.println(mockList1.get(0));   //test_answer
}

三、学习了这么多,初露锋芒一下!

测验实体类

@Data
public class User {
    /**
     * 姓名,登录密码
     */

持久层DAO

public interface UserDao {
    /**
     * 依据name查找user
     * @param name
     * @return
     */
    User getUserByName(String name);
    /**
     * 保存user
     * @param user
     * @return
     */
    Integer saveUser(User user);
}

事务层Service接口

public interface UserService {
    /**
     * 依据name查找user
     * @param name
     * @return
     */
    User getUserByName(String name);
    /**
     * 保存user
     * @param user
     * @return
     */
    Integer saveUser(User user);
}

事务层Serive完结类

@Service
public class UserServiceImpl implements UserService {
    //userDao
    @Autowired
    private UserDao userDao;
    /**
     * 依据name查找user
     * @param name
     * @return
     */
    @Override
    public User getUserByName(String name) {
        try {
            return userDao.getUserByName(name);
        } catch (Exception e) {
            throw new RuntimeException("查询user反常");
        }
    }
    /**
     * 保存user
     * @param user
     * @return
     */
    @Override
    public Integer saveUser(User user) {
        if (userDao.getUserByName(user.getName()) != null) {
            throw new RuntimeException("用户名已存在");
        }
        try {
            return userDao.saveUser(user);
        } catch (Exception e) {
            throw new RuntimeException("保存用户反常");
        }
    }
}

现在咱们的Service写好了,想要单元测验一下,可是Dao是其他人开发的,现在还没有写好,那咱们如何测验呢?

public class UserServiceTest {
    /**
     * Mock测验:依据name查询user
     */
    @Test
    public void getUserByNameTest() {
        // mock目标
        final UserDao userDao = mock(UserDao.class);
        final UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(userDao);
        // stub调用
        final User user = new User();
        user.setName("admin");
        user.setPassword("pass");
        when(userDao.getUserByName("admin")).thenReturn(user);
        // 履行待测验办法
        final User user1 = userService.getUserByName("admin");
        System.out.println("查询成果:" + JacksonUtil.obj2json(user1));  //查询成果:{"name":"admin","password":"pass"}
        // 验证mock目标交互
        verify(userDao).getUserByName(anyString());
        // 验证查询成果
        Assert.assertNotNull("查询成果为空!", user1);
        Assert.assertEquals("查询成果错误!", "admin", user1.getName());
    }
    /**
     * Mock测验:保存user
     */
    @Mock
    private UserDao userDao;
    @InjectMocks
    private UserServiceImpl userService;
    @Test
    public void saveUserTest() throws Exception{
        // 履行注解初始化
        MockitoAnnotations.initMocks(this);
        // mock目标stub操作
        final User user = new User();
        user.setName("admin");
        user.setPassword("pass");
        when(userDao.getUserByName("admin")).thenReturn(user).thenReturn(null);
        when(userDao.saveUser(any(User.class))).thenReturn(1);
        // 验证用户名重复的状况
        try {
            userService.saveUser(user);
            throw new Exception();  //走到这儿阐明验证失利
        } catch (RuntimeException e) {
            System.out.println("重复用户名保存失利-测验经过");   //重复用户名保存失利-测验经过
        }
        verify(userDao).getUserByName("admin");
        // 验证正常保存的状况
        user.setName("user");
        final Integer integer = userService.saveUser(user);
        System.out.println("保存成果:" + integer);  //保存成果:1
        Assert.assertEquals("保存失利!", 1, integer.longValue());
        verify(userDao).saveUser(any(User.class));
        verify(userDao, times(2)).getUserByName(anyString());
    }
}

依据以上代码咱们能够知道,当咱们的待测类开发完结而依靠的类的完结还没有开发完结。此刻,咱们就能够用到咱们的Mock测验,模仿咱们依靠类的回来值,使咱们的待测类与依靠类解耦。这样,咱们就能够对咱们的待测类进行单元测了。

四、参阅文档及进一步学习~

Mockito英文版javadoc:https://javadoc.io/static/org.mockito/mockito-core/3.3.3/org/mockito/Mockito.html
Mockito中文文档(部分):https://blog.csdn.net/bboyfeiyu/article/details/52127551#35
Mockito运用教程:https://www.cnblogs.com/Ming8006/p/6297333.html
参数捕获器运用:https://www.journaldev.com/21892/mockito-argumentcaptor-captor-annotation
利用ArgumentCaptor(参数捕获器)捕获办法参数进行验证:https://www.iteye.com/blog/hotdog-916364
改动mock回来值:https://www.huangyunkun.com/2014/10/25/mockito-deep-stub-with-enum/
五分钟了解Mockitohttps://www.iteye.com/blog/liuzhijun-1512780
运用Mockito进行单元测验:https://www.iteye.com/blog/qiuguo0205-1443344
JUnit + Mockito 单元测验:https://blog.csdn.net/zhangxin09/article/details/42422643
Mockito@Mock@InjectMockhttps://www.cnblogs.com/langren1992/p/9681600.html
mockito中两种部分mock的完结,spy、callRealMethod:https://www.cnblogs.com/softidea/p/4204389.html
Mockito 中被 Mocked 的目标特点及办法的默许值:https://www.cnblogs.com/fnlingnzb-learner/p/10635250.html
单元测验东西之Mockitohttps://blog.csdn.net/qq_32140971/article/details/90598454
引入Mockito测验用@Spy@Mockhttps://blog.csdn.net/message_lx/article/details/83308114
Mockito初探(含实例):https://www.iteye.com/blog/sgq0085-2031319
测验覆盖率计算:https://blog.csdn.net/lvyuan1234/article/details/82836052?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
测验覆盖率无法计算处理:https://blog.csdn.net/zhanglei082319/article/details/81536398