乐趣区

关于mockito:一文浅谈Mockito使用-京东云技术团队

一、后期筹备~

1、筹备工作

<!--mockito 依赖 -->a
<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/
  • 五分钟理解 Mockito:https://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 与 @InjectMock:https://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
  • 单元测试工具之 Mockito:https://blog.csdn.net/qq_32140971/article/details/90598454
  • 引入 Mockito 测试用 @Spy 和 @Mock:https://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

作者:京东批发 秦浩然

起源:京东云开发者社区 转载请注明起源

退出移动版