mockito example
关于Mockito的例子,翻译自官网:javaDoc
1. mock
下面这个例子mock一个List对象作为演示,实际上,请不要mock一个List,尽量使用一个真实的List对象来完成我们的测试用例 。
//为了使代码更加整洁可读,把Mockito类静态方法都引入来。
import static org.mockito.Mockito.*;
//生成一个mock实例
List mockedList = mock(List.class);
//使用mock实例
mockedList.add("one");
mockedList.clear();
//验证
verify(mockedList).add("one");
verify(mockedList).clear();
一旦创建一个mock实例,这个mock实例会记录所有与外部对象之间的交互过程,包括:方法调用、传入参数、调用次数等等。在这些基础上,你可以选择验证你所期望的交互。
2. stubbing
//类和接口都可以mock
LinkedList mockedList = mock(LindList.class);
//stubbing
when(mockedList.get(0).thenReturn("first");
when(mockedList.get(1).thenReturn(new RuntimeException());
//打印查看结果:"first"
System.out.println(mockedList.get(0));
//下面语句会抛出一个runtime excpetion
System.out.println(mockedList.get(1));
//下面语句会打印"null",因为我们没有为get(999)提供stub
System.out.println(mockedList.get(999));
//通常不需要验证一个stubbed的调用
//stubbed的前提是,你的测试代码需要关注并基于get(0)的返回值继续运行,如果你的代码不需要关注get(0)的返回值,则不需要stubbed
verify(mockedList).get(0);
- 默认情况下,所有mock实例的方法都会有一个默认的返回值:null、基本类型/基本包装类型、一个空的集合。mockito自动判断什么情况下使用哪种返回值,比如:int/Integer 返回0 ; boolean/Boolean 返回false
- stubbing是可以被覆盖的,例如,你可以把common的stubbing代码抽出来统一初始化,在具体某个test case再覆盖某个stubbing。但是需要注意的是:这些common的stubbing代码被覆盖太多的话,有可能是潜在的代码坏味道。
- 一旦对某个mock方法stubbed后,那么这个方法调用总是返回一个stubbed值,不管调用多少次,都会返回固定的stubbed值。
- 对同一个方法,用相同的参数stubbing,以最后一次以准。
3. Argument matchers
当我们对某个方法构建stubbing时,需要指定传入参数来定义来返回特定stubbed对象 , 当test case调用stubbing方法时,mockito据实际传入的传参数来判断需要返回哪个stubbed对象。 mockito使用java内置的equals()方法来对比参数。 但是,有时我们需要再加灵活的参数匹配方式。
//stubbing使用内置的anyInt()参数匹配器
when(mockedList.get(andyInt())).thenReturn("object");
//stubbing时使用自定义的参数匹配器,假设 isValid()方法返回你定义的org.hamcrest.Matcher实现
when(mockedList.contains(argThat(isValid()))).thenRenturn("element);
//下面代码将会打印 "object"
System.out.pringln(mockedList.get(999));
//使用参argument matcher来验证
verify(mockedList).get(anyInt());
//使用java 8 lambdas写argument matchers
verify(mockedList).add(argThat(someString -> someString.length() > 5));
参数匹配(argument matchers)提供更加灵活的验证方式和stubbing . 点这里 查看关于客制化Argument matchers,或者 这里 hamcrest matchers的例子,
更多关于如何实现自定义的argument matchers,查看 java doc ArgumentMatcher
要适度,合理地使用复杂的argument matchers;尽量常用equals(),或者偶尔使用anyX() matchers 以便于编写简单,干净,便以理解的测试代码。如果可以,尽量重构那些使用复杂argument matchers的代码,尽量应用equals()方法,甚至实现自定义的equals()方法来完成测试代码。
- 使用argument matchers需要注意的地方:
- 如果某个方法调用使用了argument matchers,那么其他使用调用这个方法的地方的参数也要由matchrees来提供
- 下面的例子演示了在verification时使用了两个不同的参数提供方式的错误用法。
verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));
//above is correct - eq() is also an argument matcher
verify(mock).someMethod(anyInt(), anyString(), "third argument");
//above is incorrect - exception will be thrown because third argument is given without an argument matcher.
anyObject(),eq()这两个匹配方法是不会返回一个matchers对象的,他们只是在内部的stack里记一个matcher并且返回一个dummy value(通常是一个null),这样实现的原因是为了应对java编绎器的静态类型安全检查,所以这样的话,我们不能在verified/stubbed方法之外使用anyObject(),eq()两个方法。
4. 清确地校验方法调用的次数,或至少多少次,或者一次也没有调用
//使用mock
mockedList.add("once");
mockedList.add("twice");
mockedList.add("twice");
mockedList.add("three times");
mockedList.add("three times");
mockedList.add("three times");
//下面验证调用1次, 默认使用time(1)验证调用一次
verify(mockedList).add("once");
verify(mockedList,times(1)).add("once");
//精确验证调用次数
verify(mockedList,times(2)),add("twice");
verify(mockedList,times(3)).add("three times");
//校验一次都没有调用,never()相当于times(0)
verify(mockedList,never()),add("never happened");
//校验调用次数的边界值,atLeast()或者atMost()
verify(mockedList,atLeastOnce()).add("three times");
verify(mockedList,atLeast(2)).add("three times");
verify(mockedList,atMost(5)).add("three times");
默认使用times(1)来verify,因此不需要显示使用times(1)
5. 通过exceptons来生成没有返回值的方法的stubbing
doThrow(new RuntimeException()).when(mockedList).clear();
//下面的代码执行会抛出异常
mockedList.clear();
| 第12节是关于doThrow() | doAnswer()等一类方法的详细介绍 |