MockObjects的选择:EasyMock与JMock的比较
本文假设读者已经了解了MockObjects的使用目的和基本方式,不对MockTest之类的技术作过多解释。仅提醒一句:“不要测试你的MockObjects”。
本文作为一个评测结果的同时,也可以作为EasyMock和jMock的简短教程。他们本身都很易用,可惜带的示例过于复杂,都用了过多的模式。看过本文的例子,相信就可以从容的在项目中使用了。
Java中常用的MockObjects有EasyMock和jMock等。其中EasyMock开发较早,已经出了1.1版本,而jMock前几天才刚推出了1.0 final。作为刚成熟的小弟弟,jMock有什么竞争实力呢?
本比较针对于以下几个方面,代码请见附件。
1 是否能够对具体类进行模拟(当然,对接口模拟是基本功能)
2 是否能够对方法名,参数,返回值进行动态控制
3 基本代码行数
4 是否能够对具有构造参数的具体类模拟
现在比较开始了。首先制作若干测试文件,很简单。要模拟的有一个接口和一个具体类,叫做TheInterfaceToMock和TheClassToMock,另外,提供方法SampleReturn sampleMethod(Parameter p);以及同名无参数方法。
第一个测试是针对TheInterfaceToMock,提供ParameterImpl和SampleReturnImpl作为期待的参数和返回值。
jMock代码如下:
public class JMockUsage extends MockObjectTestCase {
public void testReturnValueWithParemeter(){
// 构造Mock控制器
Mock m = new Mock(TheInterfaceToMock.class);
// 这是要测试MockObject
TheInterfaceToMock mock = (TheInterfaceToMock) m.proxy();
// 期待的返回值
SampleReturn sr = new SampleReturnImpl();
// 期待的参数
Parameter p = new ParameterImpl();
// 控制器,期待一次,方法sampleMethod,参数等于p(equals),将返回sr
m.expects(once()).method("sampleMethod")
.with(eq(p)).will(returnValue(sr));
// 正式执行mockobject
SampleReturn ret = mock.sampleMethod(new ParameterImpl());
// 确定返回值是相同的
assertSame(sr,ret);
}
}
|
相同功能的easyMcok代码如下:
public class EasyMockUsage extends TestCase {
public void testReturnValueWithParameter(){
// 构造mock控制器
MockControl control
= MockControl.createControl(TheInterfaceToMock.class);
// 这是要测试的MockObject
TheInterfaceToMock mock
= (TheInterfaceToMock) control.getMock();
// 这是要返回的值
SampleReturn sr = new SampleReturnImpl();
// 这是要传入的参数
Parameter p = new ParameterImpl();
// 恢复到记录(record)状态
control.reset();
// 首先记录sampleMethod方法
mock.sampleMethod(p);
// 设定该方法的返回值
control.setReturnValue(sr);
// 切换状态为回复(reply)
control.replay();
// 正式执行mock object的方法,明显的,参数值是equals而不是same
SampleReturn ret = mock.sampleMethod(new ParameterImpl());
// 确定返回值是需要的值
assertSame(sr,ret);
}
|
从上面的代码可以看到,同样的功能,二者的行数相差3行。其主要原因,就是easyMcok的Mock机制是基于状态,首先是录制状态,记录下来待测的方法和参数,返回值等,然后切换为回复状态。而jMock没有切换这一步,直接将参数返回值用一句话写出来。确实是一句话:期待一次,方法sampleMethod,参数等于p(equals),将返回sr。其中的一些辅助函数,例如returnValue,eq等等,位于父类MockTestCase。
结论:
1 如果不能提供MockTestCase作为父类,请使用EasyMock
2 如果需要批量或动态生成测试,请使用更规则的jMock
3 如果喜欢看起来行数少一些,请用jMock
4 如果对状态切换看不顺眼,请用Mock
|
下面进行具体类测试,一个共同的点是,二者均使用了CGLIB作为增强器,因此效率差别几乎没有。将上面的测试稍稍修改,将TheInterfaceToMock改为TheClassToMock。发生了以下变化。
用jMock,需要将import替换为新的import,代码中其他部分完全不变!
原来
import org.jmock.Mock;
import org.jmock.MockObjectTestCase;
改为:
import org.jmock.cglib.Mock;
import org.jmock.cglib.MockObjectTestCase;
|
这是个相当体贴的设计,保证了接口的一致性。对于一套API来说,同样的类却有不同的使用方法是个噩梦。
用easyMock,需要新增加一个import。并且修改一些声明的地方。
原来
import org.easymock.MockControl;
增加
import org.easymock.classextension.MockClassControl;
|
// mock控制器
MockControl control = MockClassControl.createControl(TheClassToMock.class);
|
其他部分不需要变化。虽然这有些变化,但是变化带来了其他的好处,就是:能够支持带有构造参数的具体类,而jMock不支持。这对于大量使用了PicoContainer的代码来说不啻是一个福音。
结论:
5 如果需要构造参数,只能使用easyMock
6 如果喜欢用相同的API操作并且不在乎构造参数,请用jMock
7 如果愿意等待下一版本的jMock提供构造参数支持,请用jMock
|
参考比较表:
|
EasyMock
|
jMock
|
通过接口模拟
|
是
|
是
|
控制方法有效次数
|
是
|
是
|
定制参数匹配
|
是
|
是
|
不需要状态转换
|
否
|
是
|
具体类模拟
|
是
|
是
|
具体类可有构造参数
|
是
|
否
|
接口统一
|
否
|
是
|
条件代码在一行中完成
|
否
|
是
|
支持其他参数规则,如not
|
否
|
是
|
自验证 verify()
|
是
|
是
|
综上,我选择了jMock。不过想想看,easyMock用3个类实现了大多数常用功能,很不简单啊。而jMock,如果能够提供对Constructor injection的支持就完美了。遗憾。不过从设计上看,jMock里的模式使用堪称典范,很好看哦。
本人对easyMock使用经验不多,如有谬误请指出。
下载地址:
http://www.jmock.org
http://www.easymock.org
比较代码:
http://icecloud.51.net/data/mockobjects.zip
需要:
JUnit3.8.1,Cglib2,jMock1.0,EasyMock1.1
版权声明: 本文由冰云完成,作者保留中文版权。 未经许可,不得使用于任何商业用途。 欢迎转载,但请保持文章及版权声明完整。
如需联络请发邮件:icecloud(AT)sina.com
Blog:http://icecloud.51.net
|
分享到:
相关推荐
JMock2.5.1和EasyMock3.0以及一些JUnit单元测试所需的jar,让你使用JMock和EasyMock时不用到处找相关的jar。
CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring ...EasyMock和jMock是通过使用模仿(mock)对象来测试java代码的包。它们都通过使用CGLIB来为那些没有接口的类创建模仿(mock)对象。
本压缩包内含有测试驱动的一些难以测试的源码,EasyMock/JMock/MockObjects
easymock.jar is a software testing tool, which has a lot in common wiht Jmock
它与EasyMock和jMock很相似,但是通过在执行后校验什么已经被调用,它消除了对期望行为(expectations)的需要。其它的mocking库需要你在执行前记录期望行为(expectations),而这导致了丑陋的初始化代码。
它与EasyMock和jMock很相似,但是 通过在执行后校验什么已经被调用,它消除了对期望行为(expectations)的需要。其它的mocking库需要你在执行前记录期望行为 (expectations),而这导致了丑陋的初始化代码。
CGLIB是一个强大的、高性能的代码生成库。它被广泛使用在基于代理的AOP框架(例如Spring AOP和...EasyMock和jMock作为流行的Java测试库,它们提供Mock对象的方式来支持测试,都使用了CGLIB来对没有接口的类进行代理。
groovy环境的mock工具,用于辅助单元测试.
给大家介绍在测试中使用的利器googlemock,它是Google在2008年发布的一套针对C++的Mock框架,与googletest吸取JUnit的精华一样,的它灵感同样来自去Java社区的JMock、EasyMock等Mock思想。 更多关于google...
受jMock,EasyMock和Hamcrest的启发,并在设计时考虑了C ++的细节,它可以帮助您获得更好的系统设计并编写更好的测试。 Google模拟: 提供了用于定义模拟的声明性语法, 可以轻松定义部分(混合)模拟,它们是真实...
使用 Aether 和 Maven 收集提供的依赖项 展示如何使用 Aether 收集所有依赖项(提供、测试等)的示例。 为 junit:junit-dep:jar:4.10 给出这个输出 ... org.easymock:easymock:jar:2.2 (provided)
JavaHamcrest 根据。 什么是Hamcrest? Hamcrest是一个匹配器库,可以将其组合以创建灵活的测试意图表达。 它们也已用于其他目的。 资料下载 ...同时,感谢所有在DynaMock,nMock,jMock,EasyMock和
jMock/EasyMock 对 Java 的作用(好吧,或多或少)。 编译所有目标: 这还将从其 github 存储库下载 gtest 并编译它 bazel build ... 使用 GTest 运行测试bazel test ... --test_output=errors 或者cd test ba
提供Hamcrest和其他测试工具之间的集成,包括JUnit(3和4),TestNG,jMock和EasyMock。 org.hamcrest/hamcrest-integration/1.3/hamcrest-integration-1.3.jar
提供Hamcrest和其他测试工具之间的集成,包括JUnit(3和4),TestNG,jMock和EasyMock。 org.hamcrest/hamcrest-integration/1.2/hamcrest-integration-1.2.jar
提供Hamcrest和其他测试工具之间的集成,包括JUnit(3和4),TestNG,jMock和EasyMock。 org.hamcrest/hamcrest-integration/1.0/hamcrest-integration-1.0.jar
提供Hamcrest和其他测试工具之间的集成,包括JUnit(3和4),TestNG,jMock和EasyMock。 org.hamcrest/hamcrest-integration/1.1/hamcrest-integration-1.1.jar
提供Hamcrest和其他测试工具之间的集成,包括JUnit(3和4),TestNG,jMock和EasyMock。 org.hamcrest/hamcrest-integration/1.2.1/hamcrest-integration-1.2.1.jar
单元测试使用库进行单元测试的示例图书馆包括: 1 - jMock ( ) 2 - mockito ( ) 3 - EasyMock ( )
提供Hamcrest和其他测试工具之间的集成,包括JUnit(3和4),TestNG,jMock和EasyMock。 org.hamcrest/hamcrest-integration/1.3.RC2/hamcrest-integration-1.3.RC2.jar