1 mockito概述

Mockito is a mocking framework that tastes really good. It lets you write beautiful tests with a clean & simple API. Mockito doesn’t give you hangover because the tests are very readable and they produce clean verification errors.

Mockito是一个非常不错的模拟框架。 它使您可以使用干净简单的API编写漂亮的测试。 Mockito不会给您带来麻烦,因为这些测试可读性强,并且会产生清晰的验证错误。

官方说明-how简要版本

mockito官方文档-详细版本

特性和动机github说明

其特性如下:

  • mock具体的类和接口;
  • 小注释语法糖-@Mock
  • 验证错误是干净的-单击堆栈跟踪以查看测试中失败的验证; 单击异常原因以导航到代码中的实际交互。 堆栈跟踪始终是干净的。
  • 允许按顺序进行灵活的验证(例如:按顺序进行验证,而不是每次交互都进行验证)
  • 支持精确次数和最少一次的验证
  • 使用参数匹配器(anyObject(),anyString()或refEq()进行基于反射的相等匹配)的灵活验证或存根
  • 允许创建自定义参数匹配器或使用现有的Hamcrest匹配器

2 mockito应用

gradle仓库添加相关配置如下:

repositories { jcenter() }
dependencies { testCompile "org.mockito:mockito-core:2.+" }

之于maven的相关配置,可以搜索添加pom的相关依赖;

2.1 验证互动

import static org.mockito.Mockito.*;

// mock creation
List mockedList = mock(List.class);

// using mock object - it does not throw any "unexpected interaction" exception
mockedList.add("one");
mockedList.clear();

// selective, explicit, highly readable verification
verify(mockedList).add("one");
verify(mockedList).clear();

2.2 存根方法调用

// you can mock concrete classes, not only interfaces
LinkedList mockedList = mock(LinkedList.class);

// stubbing appears before the actual execution
when(mockedList.get(0)).thenReturn("first");

// the following prints "first"
System.out.println(mockedList.get(0));

// the following prints "null" because get(999) was not stubbed
System.out.println(mockedList.get(999));

2.3 mock注解使用

public class ArticleManagerTest {

       @Mock private ArticleCalculator calculator;
       @Mock private ArticleDatabase database;
       @Mock private UserProvider userProvider;

       private ArticleManager manager;

2.4 回调

when(mock.someMethod(anyString())).thenAnswer(
     new Answer() {
         public Object answer(InvocationOnMock invocation) {
             Object[] args = invocation.getArguments();
             Object mock = invocation.getMock();
             return "called with arguments: " + Arrays.toString(args);
         }
 });

 //Following prints "called with arguments: [foo]"
 System.out.println(mock.someMethod("foo"));

2.* 更多

更多说明参加详细资料文档mockito官方文档-详细版本

3 verify

Mockito提供vertify关键字来实现校验方法是否被调用,其具体作用可总结如下:

  • 测试方法是否被调用;
  • vervify(mock,times)的具体调用次数;
@Test
    public void update() throws Exception {
        boolean result = personService.update(1, "new name");
        //验证mockDao的getPeron从未被调用
        verify(mockDao,never()).getPerson(1);
 				assertTrue("must true", result);
    		//验证是否执行过一次getPerson(1)
    		verify(mockDao, times(1)).getPerson(eq(1));
    		//验证是否执行过一次update
    		verify(mockDao, times(1)).update(isA(Person.class));
}

但是需要注意的是verify的使用限制于mack对象,对于普通对象不支持相关检测,否则会触发相关错误。

Argument passed to verify() is of type RegistrationMgrActor and is not a mock!
Make sure you place the parenthesis correctly!
See the examples of correct verifications:
    verify(mock).someMethod();
    verify(mock, times(10)).someMethod();
    verify(mock, atLeastOnce()).someMethod();
org.mockito.exceptions.misusing.NotAMockException: 
Argument passed to verify() is of type RegistrationMgrActor and is not a mock!
Make sure you place the parenthesis correctly!
See the examples of correct verifications:
    verify(mock).someMethod();
    verify(mock, times(10)).someMethod();
    verify(mock, atLeastOnce()).someMethod();
	at *******************
1 test completed, 1 failed
FAILURE: Build failed with an exception.
* What went wrong:

4 mock和spy的区别

项目中,有些函数需要处理某个服务的返回结果,而在对函数单元测试的时候,又不能启动那些服务,这里就可以利用Mockito工具。Mockito中的Mock和Spy都可用于拦截那些尚未实现或不期望被真实调用的对象和方法,并为其设置自定义行为。二者的区别在于:

1、Mock声明的对象,对函数的调用均执行mock(即虚假函数),不执行真正部分。

2、Spy声明的对象,对函数的调用均执行真正部分。

5 mockito的使用建议

这是官方网站上给出的一些mockito使用备忘:

  1. 不要mock你不曾拥有的类型;
  2. 不要试图mock值对象;
  3. 不要mock所有的东西;
  4. 用测试表达爱意;

以下是本人的一些感悟:

  1. 好的面向的对象的业务代码对于mock测试代码的编写也是有帮助的,反向的坏过程的代码会增加你写mock代码的过程。因此我们写一个逻辑的时候–最好多想想如何好用也好测–这对于函数层次结构、入参传递都是有很多需要注意的事项;
  2. 对于对值结果要求比较多的测试内容,最好直接构造你的预期结构而不是mock,mock适合测试流程,但不是所有的东西!
  3. 一开始就学着去写,而不是写完了测完了再去补,否则你写单元测试的目的完全没有达到。我们写单元测试从一开始就是希望呢能在一个不那么严格的环境里面把自己的逻辑测到!
  4. 函数不要嵌套太深,学会抽象公共方法;
  5. 特别注意静态工具类方法的使用,用的不好可能会加大自己写测试代码的复杂度。