Mockito 测试基本用法
来源:互联网 发布:windows 扩展屏幕 ipad 编辑:程序博客网 时间:2024/06/10 00:20
一、什么是mock测试,什么是mock对象?
先来看看下面这个示例:
从上图可以看出如果我们要对A进行测试,那么就要先把整个依赖树构建出来,也就是BCDE的实例。
一种替代方案就是使用mocks
从图中可以清晰的看出
mock对象就是在调试期间用来作为真实对象的替代品。
mock测试就是在测试过程中,对那些不容易构建的对象用一个虚拟对象来代替测试的方法就叫mock测试。
知道什么是mock测试后,那么我们就来认识一下mock框架—Mockito
二、什么是Mockito
除了有一个好记的名字外,Mockito尝试用不一样的方法做mocking测试,是简单轻量级能够替代EasyMock的框架。使用简单,测试代码可读性高,丰富的文档包含在javadoc中,直接在IDE中可查看文档,实例,说明。更多信息:http://code.google.com/p/mockito/
三、Stub和Mock
相同点:Stub和Mock对象都是用来模拟外部依赖,使我们能控制。
不同点:
- 而stub完全是模拟一个外部依赖,用来提供测试时所需要的测试数据。
- 而mock对象用来判断测试是否能通过,也就是用来验证测试中依赖对象间的交互能否达到预期。
- 在mocking框架中mock对象可以同时作为stub和mock对象使用,两者并没有严格区别。
更多信息:http://martinfowler.com/articles/mocksArentStubs.html
四、mockito入门实例
- Maven依赖:
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <version>1.10.19</version></dependency>
- 基本用法
@Test @SuppressWarnings("unchecked") public void testSimple() throws Exception { //创建mock对象 /*创建mock对象不能对final,Anonymous ,primitive类进行mock。*/ List<String> list = mock(List.class); //设置方法的预期返回值 when(list.get(0)).thenReturn("hello world!"); //doReturn("hello wolrd!").when(list).get(0); //可以设定返回异常 when(list.get(1)).thenThrow(new RuntimeException("exception!")); //没有返回值的void方法与其设定(支持迭代风格,第一次调用donothing,第二次dothrow抛出runtime异常) doNothing().doThrow(new RuntimeException("void exception")).when(list).clear(); list.clear(); list.clear(); verify(list, times(2)).clear(); String result = list.get(0); //验证方法调用 verify(list).get(0); //junit测试 Assert.assertEquals("hello world!", result); }
Ps:
创建mock对象不能对final,Anonymous ,primitive类进行mock。
五、参数匹配器(Argument Matcher)
Matchers类内加你有很多参数匹配器 anyInt、anyString、anyMap…..Mockito类继承于Matchers,Stubbing时使用内建参数匹配器,下例:
/** * 参数匹配器 * 如果使用参数匹配器,那么所有的参数都要使用参数匹配器,不管是stubbing还是verify的时候都一样。 */ @Test @SuppressWarnings("unchecked") public void argumentMatcherTest() throws Exception { List<String> list = mock(List.class); when(list.get(anyInt())).thenReturn("hello", "world", "hqq"); String result = list.get(0) + list.get(1); verify(list, times(2)).get(anyInt()); Assert.assertEquals("helloworld", result); Map<Integer, String> map = mock(Map.class); when(map.put(anyInt(), anyString())).thenReturn("hello"); String str = map.put(1, "world"); verify(map).put(eq(1), eq("world")); Assert.assertEquals("hello", str); }
需要注意的是:如果使用参数匹配器,那么所有的参数都要使用参数匹配器,不管是stubbing还是verify的时候都一样。
六、方法调用的验证(具体的调用次数、至少一次,一次也没有)
/** * 方法调用的验证 */ @Test public void verifyInvocate() throws Exception { List<String> list = mock(List.class); list.add("one"); list.add("twice"); list.add("twice"); list.add("three times"); list.add("three times"); list.add("three times"); verify(list, times(1)).add("one"); verify(list, times(2)).add("twice"); verify(list, times(3)).add("three times"); verify(list, times(0)).add("never added"); verify(list, atLeastOnce()).add("one"); verify(list, atLeast(2)).add("twice"); verify(list, atMost(3)).add("three times"); }
七、按顺序来验证
/** * 按顺序来验证 */ @Test @SuppressWarnings("unchecked") public void orderTest() throws Exception { // A. 单个mock对象他的方法必须按照顺序来调用。 List singleMock = mock(List.class); singleMock.add("first"); singleMock.add("second"); //为单个Mock创建一个InOrder的顺序验证 InOrder inOrderSingle = inOrder(singleMock); //验证访问次序 inOrderSingle.verify(singleMock).add("first"); inOrderSingle.verify(singleMock).add("second"); // B. 多个mock也必须按照顺序来使用 List firstMock = mock(List.class); List secondMock = mock(List.class); firstMock.add("first add"); secondMock.add("second add"); InOrder inOrderMulti = inOrder(firstMock, secondMock); inOrderMulti.verify(firstMock).add("first add"); inOrderMulti.verify(secondMock).add("second add"); }
八、 确保交互操作没有执行在Mock对象上
//使用mock对象——仅和mockOne在进行交互mockOne.add("one");//普通验证verify(mockOne).add("one");//验证某个交互是否从未被执行verify(mockOne, never()).add("two");//验证其它Mock对象没有交互过verifyZeroInteractions(mockTwo, mockThree);
九、查找多余的调用
//使用mockmockedList.add("one");mockedList.add("two");verify(mockedList).add("one");//下面的验证将会失败verifyNoMoreInteractions(mockedList);
十、快速创建mock对象——@Mock注解
@RunWith(MockitoJUnitRunner.class)public class AnnotationMockTest { @Mock List<String> list; @Mock private User user; @Test public void test() throws Exception { when(list.get(0)).thenReturn("hello,mockito"); System.out.println(list.get(0)); } @Test public void userTest() throws Exception { when(user.getName()).thenReturn("heqianqian"); System.out.println(user.getName()); }}
十一、迭代式的测试
有时我们需要为同一个方法调用的返回值或者异常做测试桩。典型的运用就是使用Mock迭代器。Mockito的早期版本是没有这个特性的。比如,开发人员可能会使用Iterable或者是简单的集合来替代迭代器。这些方法为做测试桩提供了更自然的方式,在一些场景中为连续的调用做测试桩会很有用,比如:
@RunWith(MockitoJUnitRunner.class)public class IteratorMockitoTest { @Mock List<String> list; @Test public void iteratorTest() throws Exception { when(list.get(0)).thenReturn("one","two","three"); //返回one System.out.println(list.get(0)); //返回two System.out.println(list.get(0)); //之后都是three System.out.println(list.get(0)); System.out.println(list.get(0)); }}
十二、为回调做测试桩
为泛型接口Answer打桩。
public class CallbackMockitoTest { @Test @SuppressWarnings("unchecked") public void callbackTest() throws Exception { List<String> list = mock(List.class); list.add("hello"); when(list.get(0)).thenAnswer(new Answer<String>() { @Override public String answer(InvocationOnMock invocationOnMock) throws Throwable { //获得函数调用的参数 Object[] args = invocationOnMock.getArguments(); //获得Mock对象本身 Object mock = invocationOnMock.getMock(); return "called with arguments:" + args[0].toString(); } }); System.out.println(list.get(0)); }}
十三、监控真实对象
你可以为真实对象创建一个监控(spy)对象。当你使用这个spy对象时,真实的方法也会调用(除非这个函数被打桩)。实际中应该有节制的spy对象,比如在处理遗留代码时:
List list = new LinkedList();List spy = spy(list); //你可以随意的为某些函数打桩: when(spy.size()).thenReturn(100); //通过spy对象调用真实对象的方法: spy.add("one"); spy.add("two"); //打印list的第一个元素 System.out.println(spy.get(0)); //因为size()函数被打桩了,所以这里返回100 System.out.println(spy.size()); //验证交互 verify(spy).add("one"); verify(spy).add("two");
有时候,在监控对象上使用when(Object)来进行打桩是不可能或者不切实际的。因此在使用spy的时候,请考虑doReturn|Answer|Throw() 这一系列的方法来打桩。例如:
List list = new LinkedList(); List spy = spy(list); //不可能:因为当调用spy.get(0)时会调用真实对象的get(0)函数,此时会发生IndexOutOfBoundsException,因为真实list对象是空的。 when(spy.get(0)).thenReturn("foo"); //你需要使用doReturn来进行打桩。 doReturn("foo").when(spy).get(0);
Mockito并不会为真实对象代理函数调用,实际上它会复制真实对象。所以,如果你保留了真实对象并与其交互,不要期望从监控对象得到正确的结果。当你在监控对象上调用一个没有被打桩的函数时,并不会调用真实对象的对应函数,因此你不会在真实对象上看到任何结果。
因此结论就是:当你在监控一个真实对象时,你想为这个真实对象的函数做测试桩,那么就是在自找麻烦。或者你根本不应该验证这些函数。
- Mockito 测试基本用法
- mockito测试
- Mockito测试
- Mockito基本教程
- Mockito注解基本例子
- Java测试包Mockito
- Mockito测试实例
- mockito测试入门
- Mockito测试实例
- 模拟测试框架-Mockito
- mockito mock测试框架
- 测试-TestNG and Mockito
- Mockito测试框架入门
- 测试工具(junit, mockito)
- Mockito测试静态方法
- mockito测试入门学习
- Junit测试基本用法
- 强大的Mockito测试框架
- 高性能mysql笔记(一)并发 事务 引擎
- [PAT-乙级]1061.判断题
- 笔记本安装双系统教程
- C++学习笔记
- 莫名其妙 对话框 create 失败, 错误见图
- Mockito 测试基本用法
- 最喜欢的诗文
- 模块5
- 内部类大展身手 ———— 多个内部类以不同的方式实现同一个接口,或继承同一个类
- [PAT-乙级]1062.最简分数
- 百度2017春招<度度熊买帽子问题>Java代码
- 怎么把下划线整体下移上移,让下划线和文字距离随便调整。
- FFT频谱泄露和加窗 (一)
- xsd 学习