Mockito是mocking框架,它让你用简洁的API做测试。而且Mockito简单易学,它可读性强和验证语法简洁。
Mockito 是一个针对 Java 的单元测试模拟框架,它与 EasyMock 和 jMock 很相似,都是为了简化单元测试过程中测试上下文 ( 或者称之为测试驱动函数以及桩函数 ) 的搭建而开发的工具
相对于 EasyMock 和 jMock,Mockito 的优点是通过在执行后校验哪些函数已经被调用,消除了对期望行为(expectations)的需要。其它的 mocking 库需要在执行前记录期望行为(expectations),而这导致了丑陋的初始化代码。
maven依赖:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
ReflectionTestUtils.setField(Object targetObject, String name, Object value);
@Service
public class BookServiceImpl implements IBookService{
@Autowired
private IBookDao bookDao;
}
//将模拟的对象注入到构造的测试类中
ReflectionTestUtils.setField(bookService, "bookDao", bookDao);
方法名 | 描述 |
---|---|
Mockito.mock(classToMock) | 模拟对象 |
Mockito.verify(mock) | 验证行为是否发生 |
Mockito.when(methodCall).thenReturn(value1).thenReturn(value2) | 触发时第一次返回value1,第n次都返回value2 |
Mockito.doThrow(toBeThrown).when(mock).[method] | 模拟抛出异常。 |
Mockito.mock(classToMock,defaultAnswer) | 使用默认Answer模拟对象 |
Mockito.when(methodCall).thenReturn(value) | 参数匹配 |
Mockito.doReturn(toBeReturned).when(mock).[method] | 参数匹配(直接执行不判断) |
Mockito.when(methodCall).thenAnswer(answer)) | 预期回调接口生成期望值 |
Mockito.doAnswer(answer).when(methodCall).[method] | 预期回调接口生成期望值(直接执行不判断) |
Mockito.spy(Object) | 用spy监控真实对象,设置真实对象行为 |
Mockito.doNothing().when(mock).[method] | 不做任何返回 |
Mockito.doCallRealMethod().when(mock).[method] //等价于Mockito.when(mock.[method]).thenCallRealMethod(); | 调用真实的方法 |
reset(mock) | 重置mock |
验证行为是否发生
//模拟创建一个List对象
List<Integer> mock = Mockito.mock(List.class);
//调用mock对象的方法
mock.add(1);
mock.clear();
//验证方法是否执行
Mockito.verify(mock).add(1);
Mockito.verify(mock).clear();
多次触发返回不同值
//mock一个Iterator类
Iterator iterator = mock(Iterator.class);
//预设当iterator调用next()时第一次返回hello,第n次都返回world
Mockito.when(iterator.next()).thenReturn("hello").thenReturn("world");
//使用mock的对象
String result = iterator.next() + " " + iterator.next() + " " + iterator.next();
//验证结果
Assert.assertEquals("hello world world",result);
模拟抛出异常
@Test(expected = IOException.class)//期望报Io异常
public void when_thenThrow() throws IOException{
OutputStream mock = Mockito.mock(OutputStream.class);
//预设当流关闭时抛出异常
Mockito.doThrow(new IOException()).when(mock).close();
mock.close();
}
使用默认Answer模拟对象
RETURNS_DEEP_STUBS 是创建mock对象时的备选参数之一
以下方法deepstubsTest和deepstubsTest2是等价的
@Test
public void deepstubsTest(){
A a=Mockito.mock(A.class,Mockito.RETURNS_DEEP_STUBS);
Mockito.when(a.getB().getName()).thenReturn("Beijing");
Assert.assertEquals("Beijing",a.getB().getName());
}
@Test
public void deepstubsTest2(){
A a=Mockito.mock(A.class);
B b=Mockito.mock(B.class);
Mockito.when(a.getB()).thenReturn(b);
Mockito.when(b.getName()).thenReturn("Beijing");
Assert.assertEquals("Beijing",a.getB().getName());
}
class A{
private B b;
public B getB(){
return b;
}
public void setB(B b){
this.b=b;
}
}
class B{
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public String getSex(Integer sex){
if(sex==1){
return "man";
}else{
return "woman";
}
}
}
参数匹配
@Test
public void with_arguments(){
B b = Mockito.mock(B.class);
//预设根据不同的参数返回不同的结果
Mockito.when(b.getSex(1)).thenReturn("男");
Mockito.when(b.getSex(2)).thenReturn("女");
Assert.assertEquals("男", b.getSex(1));
Assert.assertEquals("女", b.getSex(2));
//对于没有预设的情况会返回默认值
Assert.assertEquals(null, b.getSex(0));
}
class B{
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public String getSex(Integer sex){
if(sex==1){
return "man";
}else{
return "woman";
}
}
}
匹配任意参数
Mockito.anyInt() 任何int值
Mockito.anyLong() 任何long值
Mockito.anyString() 任何String值
等等
@Test
public void with_unspecified_arguments(){
List list = Mockito.mock(List.class);
//匹配任意参数
Mockito.when(list.get(Mockito.anyInt())).thenReturn(1);
Mockito.when(list.contains(Mockito.argThat(new IsValid()))).thenReturn(true);
Assert.assertEquals(1,list.get(1));
Assert.assertEquals(1,list.get(999));
Assert.assertTrue(list.contains(1));
Assert.assertTrue(!list.contains(3));
}
class IsValid extends ArgumentMatcher<List>{
@Override
public boolean matches(Object obj) {
return obj.equals(1) || obj.equals(2);
}
}
使用了参数匹配,那么所有的参数都必须通过matchers来匹配
Mockito继承Matchers,anyInt()等均为Matchers方法
当传入两个参数,其中一个参数采用任意参数时,指定参数需要matchers来对比
Comparator comparator = mock(Comparator.class);
comparator.compare("nihao","hello");
//如果你使用了参数匹配,那么所有的参数都必须通过matchers来匹配
Mockito.verify(comparator).compare(Mockito.anyString(),Mockito.eq("hello"));
//下面的为无效的参数匹配使用
//verify(comparator).compare(anyString(),"hello");
自定义参数匹配
Mockito.argThat(Matcher matcher) 应用自定义的规则
@Test
public void argumentMatchersTest(){
//创建mock对象
List<String> mock = mock(List.class);
//argThat(Matches<T> matcher)方法用来应用自定义的规则,可以传入任何实现Matcher接口的实现类。
Mockito.when(mock.addAll(Mockito.argThat(new IsListofTwoElements()))).thenReturn(true);
Assert.assertTrue(mock.addAll(Arrays.asList("one","two","three")));
}
class IsListofTwoElements extends ArgumentMatcher<List>
{
public boolean matches(Object list)
{
return((List)list).size()==3;
}
}
预期回调接口生成期望值
@Test
public void answerTest(){
List mockList = Mockito.mock(List.class);
//使用方法预期回调接口生成期望值(Answer结构)
Mockito.when(mockList.get(Mockito.anyInt())).thenAnswer(new CustomAnswer());
Assert.assertEquals("hello world:0",mockList.get(0));
Assert.assertEquals("hello world:999",mockList.get(999));
}
private class CustomAnswer implements Answer<String> {
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
return "hello world:"+args[0];
}
}
等价于:(也可使用匿名内部类实现)
@Test
public void answer_with_callback(){
//使用Answer来生成我们我们期望的返回
Mockito.when(mockList.get(Mockito.anyInt())).thenAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
return "hello world:"+args[0];
}
});
Assert.assertEquals("hello world:0",mockList.get(0));
Assert. assertEquals("hello world:999",mockList.get(999));
}
预期回调接口生成期望值(直接执行)
@Test
public void testAnswer1(){
List<String> mock = Mockito.mock(List.class);
Mockito.doAnswer(new CustomAnswer()).when(mock).get(Mockito.anyInt());
Assert.assertEquals("大于三", mock.get(4));
Assert.assertEquals("小于三", mock.get(2));
}
public class CustomAnswer implements Answer<String> {
public String answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
Integer num = (Integer)args[0];
if( num>3 ){
return "大于三";
} else {
return "小于三";
}
}
}
修改对未预设的调用返回默认期望(指定返回值)
//mock对象使用Answer来对未预设的调用返回默认期望值
List mock = Mockito.mock(List.class,new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return 999;
}
});
//下面的get(1)没有预设,通常情况下会返回NULL,但是使用了Answer改变了默认期望值
Assert.assertEquals(999, mock.get(1));
//下面的size()没有预设,通常情况下会返回0,但是使用了Answer改变了默认期望值
Assert.assertEquals(999,mock.size());
用spy监控真实对象,设置真实对象行为
@Test(expected = IndexOutOfBoundsException.class)
public void spy_on_real_objects(){
List list = new LinkedList();
List spy = Mockito.spy(list);
//下面预设的spy.get(0)会报错,因为会调用真实对象的get(0),所以会抛出越界异常
//Mockito.when(spy.get(0)).thenReturn(3);
//使用doReturn-when可以避免when-thenReturn调用真实对象api
Mockito.doReturn(999).when(spy).get(999);
//预设size()期望值
Mockito.when(spy.size()).thenReturn(100);
//调用真实对象的api
spy.add(1);
spy.add(2);
Assert.assertEquals(100,spy.size());
Assert.assertEquals(1,spy.get(0));
Assert.assertEquals(2,spy.get(1));
Assert.assertEquals(999,spy.get(999));
}
不做任何返回
@Test
public void Test() {
A a = Mockito.mock(A.class);
//void 方法才能调用doNothing()
Mockito.doNothing().when(a).setName(Mockito.anyString());
a.setName("bb");
Assert.assertEquals("bb",a.getName());
}
class A {
private String name;
private void setName(String name){
this.name = name;
}
private String getName(){
return name;
}
}
调用真实的方法
@Test
public void Test() {
A a = Mockito.mock(A.class);
//void 方法才能调用doNothing()
Mockito.when(a.getName()).thenReturn("bb");
Assert.assertEquals("bb",a.getName());
//等价于Mockito.when(a.getName()).thenCallRealMethod();
Mockito.doCallRealMethod().when(a).getName();
Assert.assertEquals("zhangsan",a.getName());
}
class A {
public String getName(){
return "zhangsan";
}
}
重置mock
@Test
public void reset_mock(){
List list = mock(List.class);
Mockito. when(list.size()).thenReturn(10);
list.add(1);
Assert.assertEquals(10,list.size());
//重置mock,清除所有的互动和预设
Mockito.reset(list);
Assert.assertEquals(0,list.size());
}
使用@Mock注释
public class MockitoTest {
@Mock
private List mockList;
//必须在基类中添加初始化mock的代码,否则报错mock的对象为NULL
public MockitoTest(){
MockitoAnnotations.initMocks(this);
}
@Test
public void AnnoTest() {
mockList.add(1);
Mockito.verify(mockList).add(1);
}
}
指定测试类使用运行器:MockitoJUnitRunner
@RunWith(MockitoJUnitRunner.class)
public class MockitoTest2 {
@Mock
private List mockList;
@Test
public void shorthand(){
mockList.add(1);
Mockito.verify(mockList).add(1);
}
}
参考文档:https://www.cnblogs.com/Ming8006/p/6297333.html