简介
一、什么是mock测试,什么是mock对象?
先来看看下面这个示例:
从上图可以看出如果我们要对A进行测试,那么就要先把整个依赖树构建出来,也就是BCDE的实例。
一种替代方案就是使用mocks
从图中可以清晰的看出
mock对象就是在调试期间用来作为真实对象的替代品。
mock测试就是在测试过程中,对那些不容易构建的对象用一个虚拟对象来代替测试的方法就叫mock测试。
知道什么是mock测试后,那么我们就来认识一下mock框架---Mockito
Stub和Mock
相同点:Stub和Mock对象都是用来模拟外部依赖,使我们能控制。
不同点:而stub完全是模拟一个外部依赖,用来提供测试时所需要的测试数据。而mock对象用来判断测试是否能通过,也就是用来验证测试中依赖对象间的交互能否达到预期。在mocking框架中mock对象可以同时作为stub和mock对象使用,两者并没有严格区别。
mockito案例
pom
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.8.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
package com.jmock.demo;
import org.junit.Test;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import static org.mockito.Mockito.*;
/**
* Created by zhongmin on 2016/9/8.
*/
public class SimpleTest {
@Test
public void simpleTest(){
//创建mock对象,参数可以是类,也可以是接口
List<String> list = mock(List.class);
//设置方法的预期返回值
when(list.get(0)).thenReturn("helloworld");
String result = list.get(0);
//验证方法调用(是否调用了get(0))
verify(list).get(0);
//junit测试
Assert.assertEquals("helloworld", result);
}
@Test
public void argumentMatchersTest(){
//创建mock对象
List<String> mock = mock(List.class);
//参数匹配,anyInt()匹配任何参数
when(mock.get(anyInt())).thenReturn("hello").thenReturn("world");
String result = mock.get(100)+" "+mock.get(201);
//验证方法是否调用2次
verify(mock,times(2)).get(anyInt());
Assert.assertEquals("hello world",result);
}
@Test
public void argumentMatchersAnyTest(){
//创建mock对象
Map mapMock = mock(Map.class);
//参数匹配起匹配map参数
when(mapMock.put(anyInt(),anyString())).thenReturn("world");
mapMock.put(1,"hello");
//校验方法是否被调用,注意参数匹配,由于使用了匹配器,verify也要使用匹配器,如下几种用法
// verify(mapMock).put(anyInt(),eq("hello")); //正确
// verify(mapMock).put(eq(1),eq("hello")); //正确
// verify(mapMock).put(eq(1),"hello"); //错误
// verify(mapMock).put(1,"hello"); //正确
// verify(mapMock).put(anyInt(),anyString()); //正确
verify(mapMock).put(1,eq("hello")); //错误
}
/**
* 参数行为测试
*/
@Test
public void verifyTestTest(){
List<String> mock = mock(List.class);
List<String> mock2 = mock(List.class);
mock.get(0);
mock.get(1);
mock.get(2);
mock2.get(0);
verify(mock).get(2);
verify(mock,never()).get(3);
verifyNoMoreInteractions(mock);
}
/**
* Answer接口(方法逾期回调接口)
* PS:mock对象的方进行调用预期的设定可以通过thenReturn()来指定返回值,thenThrow()指定返回时所抛异常,
* 通常来说这两个方法足以应对一般的需求。
* 但有时我们需要自定义方法执行的返回结果,Answer接口就是满足这样的需求而存在的。
*/
@Test
public void answerTest(){
List<String> mock = mock(List.class);
//
when(mock.get(4)).thenAnswer(new CustomAnswer());
doAnswer(new CustomAnswer()).when(mock).clear();
}
private class CustomAnswer implements Answer<String>{
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
Integer num = (Integer)args[0];
System.out.println("num = "+num);
if(num>3 ){
return"yes";
}else{
throw new RuntimeException();
}
}
}
/**
* 自定义参数匹配器
*/
@Test
public void argumentDefMatchersTest(){
List mock = mock(List.class);
//设置自定义参数匹配器
when(mock.addAll(argThat(new IsListOfTwoElements()))).thenReturn(true);
mock.addAll(Arrays.asList("one","two","three"));
verify(mock).addAll(argThat(new IsListOfTwoElements()));
}
private class IsListOfTwoElements extends ArgumentMatcher<List>{
@Override
public boolean matches(Object argument) {
return ((List)argument).size()==2;
}
}
@Test
public void argumentCaptorTest(){
List mock = mock(List.class);
List mock2 = mock(List.class);
mock.add("John");
mock2.add("Brian");
mock2.add("Jim");
//实例化参数捕获器
ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(String.class);
//捕获输入的参数
verify(mock).add(argumentCaptor.capture());
Assert.assertEquals("John",argumentCaptor.getValue());
//当有多个参数调用,捕获最后输入的参数
verify(mock2,times(2)).add(argumentCaptor.capture());
Assert.assertEquals("Jim",argumentCaptor.getValue());
//捕获所有参数
Assert.assertArrayEquals(new Object[]{"Brian","Jim"},argumentCaptor.getAllValues().toArray());
}
@Test
public void spyTest(){
List list = new LinkedList();
List spy = spy(list);
when(spy.size()).thenReturn(100);
spy.add("one");
spy.add("two");
System.out.println(spy.get(0));
System.out.println(spy.size());
verify(spy).add("one");
verify(spy).add("two");
}
}
注解DEMO
package com.jmock.demo;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import java.util.LinkedList;
import java.util.List;
import static org.mockito.Mockito.*;
/**
* Created by zhongmin on 2016/9/9.
*/
public class MockitoTest {
@Mock
private List<String> list;
@Spy
private List<String> spyList = new LinkedList<String>();
@Before
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
@Test
public void simpleTest(){
//创建mock对象,参数可以是类,也可以是接口
// List<String> list = mock(List.class);
//设置方法的预期返回值
when(list.get(0)).thenReturn("helloworld");
String result = list.get(0);
//验证方法调用(是否调用了get(0))
verify(list).get(0);
//junit测试
Assert.assertEquals("helloworld", result);
}
@Test
public void spyTest(){
// List list = new LinkedList();
// List spy = spy(list);
when(spyList.size()).thenReturn(100);
spyList.add("one");
spyList.add("two");
System.out.println(spyList.get(0));
System.out.println(spyList.size());
verify(spyList).add("one");
verify(spyList).add("two");
}
}
推荐教程:http://wenku.baidu.com/view/8def451a227916888486d73f.html