EasyMock 、mockito、powermock 参考:https://www.cnblogs.com/huangbin/archive/2013/04/27/3047671.html
EasyMock之后流行的mock工具。相对EasyMock学习成本低,而且具有非常简洁的API,测试代码的可读性很高。
mockito可以在https://code.google.com/p/mockito/上下载,如果使用maven可以如下引入:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
使用mockito大致可以划分为以下几个步骤:
① 使用 mockito 生成 Mock 对象;
② 定义(并非录制) Mock 对象的行为和输出(expectations部分);
③ 调用 Mock 对象方法进行单元测试;
④ 对 Mock 对象的行为进行验证。
现在用一个例子来简单呈现以上的步骤:
首先静态导入mockito的方法:
import static org.mockito.Mockito.*;
例2.1 mockito第一个例子
@Test
public void testMockMethod() {
Class1Mocked obj=mock(Class1Mocked.class);①
when(obj.hello("z3")).thenReturn("hello l4");②
String actual=obj.hello("z3");③
assertEquals("hello l4",actual);
verify(obj).hello("z3");④
//verify(obj,times(1)).hello("z3"); //可以加参数验证次数
}
可以看到与EasyMock相比,少了切换到播放状态一步。这是很自然的,本来就不是录制而谈播放呢,而在验证阶段可以通过增加参数(time(int)、atLeastOnce()、atLeast(int)、never()等)来精确验证调用次数。
而如果要验证调用顺序可以如下控制:
例2.2 验证顺序
@Test
public void testMockMethodInOrder() {
Class1Mocked objOther = mock(Class1Mocked.class);
Class1Mocked objCn = mock(Class1Mocked.class);
when(objOther.hello("z3")).thenReturn("hello l4");
when(objCn.hello("z3")).thenReturn("hello 张三");
String other = objOther.hello("z3");
assertEquals("hello l4", other);
String cn = objCn.hello("z3");
assertEquals("hello 张三", cn);
InOrder inOrder = inOrder(objOther, objCn); //此行并不决定顺序,下面的两行才开始验证顺序
inOrder.verify(objOther).hello("z3");
inOrder.verify(objCn).hello("z3");
}
在之前的介绍的模拟操作中,我们总是去模拟一整个类或者对象,对于没有使用 When().thenReturn()方法指定的函数,系统会返回各种类型的默认值(具体值可参考官方文档)。而局部模拟创建出来的模拟对象依然是原系统对象,虽然可以使用方法When().thenReturn()来指定某些具体方法的返回值,但是没有被用此函数修改过的函数依然按照系统原始类的方式来执行,下面对非局部模拟和局部模拟分别举例来说明:
例2.3 非局部模拟
@Test
public void testSkipExpect() {
Class1Mocked obj = mock(Class1Mocked.class);
assertEquals(null, obj.hello("z3"));
obj.show();
verify(obj).hello("z3");
verify(obj).show();
}
上面的代码省略了expectations部分(即定义代码行为和输出),运行该测试可以看到hello方法默认返回null(show方法本来就是无返回值的),而且在控制台中两个方法都没有输出任何语句。
mockito的局部模拟有两种方式,一种是doCallRealMethod()方式,另一种是spy()方式。
例2.4 局部模拟doCallRealMethod ()方式
@Test
public void testCallRealMethod () {
Class1Mocked obj = mock(Class1Mocked.class);
doCallRealMethod().when(obj).hello("z3");
assertEquals("hello z3",obj.hello("z3"));
assertEquals(null,obj.hello("l4"));
obj.show();
verify(obj).hello("z3");
verify(obj).hello("l4");
verify(obj).show();
}
运行这个测试会发现在执行hello("z3")时会执行原有的代码,而执行hello("l4")时则是返回默认值null且没有输出打印,执行show()同样没有输出打印。
例2.5 局部模拟spy()方式
@Test
public void testSpy() {
Class1Mocked obj = spy(new Class1Mocked());
doNothing().when(obj).show();
assertEquals("hello z3",obj.hello("z3"));
obj.show();
verify(obj).hello("z3");
verify(obj).show();
}
运行这个测试会发现在执行hello("z3")时会执行原有的代码,但是执行show()时在控制台中没有打印语句。
但值得注意的是在mockito的psy()方式模拟中expectations部分使用的语法不同,执行起来存在微妙的不同,如下:
例2.6 值得注意的“陷阱”
@Test
public void testSpy2() {
Class1Mocked obj = spy(new Class1Mocked());
when(obj.hello("z3")).thenReturn("hello l4");
assertEquals("hello l4",obj.hello("z3"));
verify(obj).hello("z3");
}
上面的代码虽然能顺利运行,但在控制台中输出了hello z3,说明实际的代码仍然执行了,只是mockito在最后替换了返回值。但下面的代码就不会执行实际的代码:
@Test
public void testSpy3() {
Class1Mocked obj = spy(new Class1Mocked());
doReturn("hello l4").when(obj).hello("z3");
assertEquals("hello l4",obj.hello("z3"));
verify(obj).hello("z3");
}