蛰脚踝的天蝎 2010-08-27
我们都有这种经验,测试在我们软件编码过程中占据了大部分时间,有时候觉得软件业务代码好写,但测试代码却难写了,单元测试是把自己的代码交托给测试同学和其他同学前的承诺。
为了获得更好的代码质量,我们一般都会用几好种工具,其中FindBugs和Emma(http://update.eclemma.org)就是常用的。
在测试与其它系统有交互的功能块,并且其它系统的稳定性未知的情况下,Mock就得派上用场了,否则测试起来极其吃力,并且效率低下。
下面简单介绍下两种Mock测试框架:JMock【http://www.jmock.org】和Mockito【http://www.mockito.org】。
一、前提说明
两个类:一个被Mock的对象(MayMockObject),一个被测试的对象(MainTstObject)。
很明显,我们的任务是测试MainTstObject,而该类引用了MayMockObject,为了测试的进行,我们模拟MayMockObject的实例。
测试用例类:MainTstObjectJMockTest和MainTstObjectMockitoTest。
二、依赖加入
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
<version>4.4</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
<version>1.8.5</version>
</dependency>
<dependency>
<groupId>jmock</groupId>
<artifactId>jmock</artifactId>
<scope>test</scope>
<version>2.5.1</version>
</dependency>
当然,如果工程不是基于Maven构架的,可以直接加入相应的Jar也行。
三、外接接口(将被Mock的对象)
publicinterfaceMayMockObject{
publicStringgetString(Stringstr);
}
四、功能类(被测试的类)
publicclassMainTstObject{
privateMayMockObjectmayMockObject;//引用了外接接口
publicStringcreate(Stringstr1,Stringstr2){
returnstr1+this.mayMockObject.getString(str2);
}
publicvoidsetMayMockObject(MayMockObjectmayMockObject){
this.mayMockObject=mayMockObject;
}
}
五、JMock的测试用例
publicclassMainTstObjectJMockTest{
privateMockerycontext=newJUnit4Mockery();
privateMayMockObjectmayMockObject;
privateMainTstObjectmainTstObject;
@Before
publicvoidsetUp(){
this.mayMockObject=this.context.mock(MayMockObject.class);//Mock了外接接口
this.mainTstObject=newMainTstObject();
this.mainTstObject.setMayMockObject(this.mayMockObject);
}
@Test
publicvoidprocess(){
finalStringstr1="Mockito返回字符串。";
finalStringstr2="Mockito返回字符串。";
this.context.checking(newExpectations(){
{
oneOf(mayMockObject).getString(str2);
will(returnValue(""));//Mock返回值
//allowing(mayMockObject).getString(with(any(String.class)));
//will(returnValue(""));
}
});
Stringret=this.mainTstObject.create(str1,str2);
Assert.assertEquals(ret,str1);
}
@After
publicvoidtearDown(){
}
}
六、Mockito的测试用例
publicclassMainTstObjectMockitoTest{
//指定Mock的对象
@Mock
privateMayMockObjectmayMockObject;
privateMainTstObjectmainTstObject;
@Before
publicvoidsetUp(){
MockitoAnnotations.initMocks(this);//声明测试用例类
this.mainTstObject=newMainTstObject();
this.mainTstObject.setMayMockObject(this.mayMockObject);
}
@Test
publicvoidprocess(){
Stringstr1="Mockito返回字符串。";
Stringstr2="Mockito返回字符串。";
Mockito.when(this.mayMockObject.getString(str2)).thenReturn("");//Mock返回值
Stringret=this.mainTstObject.create(str1,str2);
Assert.assertEquals(ret,str1);
}
@After
publicvoidtearDown(){
}
}
七、最后
从两个测试用例可以看出,JMock和Mockito在用法上的一些区别:
1、对于要Mock的对象,JMock要显示指出来【this.mayMockObject=this.context.mock(MayMockObject.class);】;
而Mockito只是简单加上注释【@Mock】,然后声明下测试用例类即可【MockitoAnnotations.initMocks(this);】。
2、对于方法的模拟,JMock显得更加复杂了【this.context.checking(newExpectations(){
{
oneOf(mayMockObject).getString(str2);
will(returnValue(""));
}
});】
而Mockito只要简单的一行代码就行【Mockito.when(this.mayMockObject.getString(str2)).thenReturn("");】。
从上可以看出,Mockito的代码行更少,更加简洁,个人比较喜欢用Mockito,简洁易记!
另外需要注意的是:JMock只能Mock接口,也就是上面的例子中【MayMockObject】只能为接口,不能为实体类;而Mockito就没有这个限制。
当然,我们既然用Mock,就是因为只知接口,而不知其具体实现,这样说来,JMock只能Mock接口不能算是Mockito的一个优点了。