在Java中创建模拟对象的最佳框架是什么?为什么?每个框架的优缺点是什么?
我使用Mockito取得了很大的成功 .
当我尝试学习JMock和EasyMock时,我发现学习曲线有点陡峭(尽管可能只是我) .
我喜欢Mockito,因为它简单而干净的语法让我能够很快掌握 . 最小的语法旨在很好地支持常见的情况,虽然我需要做一些更复杂的事情我发现我想要的东西是支持和易于掌握的 .
这是Mockito主页上的一个(删节)示例:
import static org.mockito.Mockito.*; List mockedList = mock(List.class); mockedList.clear(); verify(mockedList).clear();
它没有那么简单 .
我能想到的唯一主要缺点是它不会模拟静态方法 .
我是PowerMock的创造者,所以显然我必须推荐它! :-)
PowerMock扩展了EasyMock和Mockito,具有mock static methods,最终甚至私有方法的能力 . EasyMock支持已经完成,但Mockito插件需要更多工作 . 我们还计划添加JMock支持 .
PowerMock并不打算替换其他框架,而是可以在其他框架不允许模拟的棘手情况下使用它 . PowerMock还包含其他有用的功能,例如suppressing static initializers和构造函数 .
JMockit project site包含大量当前模拟工具包的比较信息 .
特别是,请查看 feature comparison matrix ,其中包括EasyMock,jMock,Mockito,Unitils Mock,PowerMock,当然还有JMockit . 我尽可能地保持其准确和最新 .
我一直在JMockit取得成功 .
它有点原始且记录不足 . 它使用ASM动态重新定义类字节码,因此它可以模拟所有方法,包括静态,私有,构造函数和静态初始化器 . 例如:
import mockit.Mockit; ... Mockit.redefineMethods(MyClassWithStaticInit.class, MyReplacementClass.class); ... class MyReplacementClass { public void $init() {...} // replace default constructor public static void $clinit{...} // replace static initializer public static void myStatic{...} // replace static method // etc... }
它有一个Expectations界面,允许记录/播放场景:
import mockit.Expectations; import org.testng.annotations.Test; public class ExpecationsTest { private MyClass obj; @Test public void testFoo() { new Expectations(true) { MyClass c; { obj = c; invokeReturning(c.getFoo("foo", false), "bas"); } }; assert "bas".equals(obj.getFoo("foo", false)); Expectations.assertSatisfied(); } public static class MyClass { public String getFoo(String str, boolean bool) { if (bool) { return "foo"; } else { return "bar"; } } } }
缺点是它需要Java 5/6 .
您还可以使用Groovy查看测试 . 在Groovy中,您可以使用'as'运算符轻松模拟Java接口:
def request = [isUserInRole: { roleName -> roleName == "testRole"}] as HttpServletRequest
除了这个基本功能外,Groovy还提供了更多关于模拟前端的功能,包括强大的 MockFor 和 StubFor 类 .
MockFor
StubFor
http://docs.codehaus.org/display/GROOVY/Groovy+Mocks
我开始使用EasyMock模拟 . 很容易理解,但重播步骤有点烦人 . Mockito删除了它,也有一个更清晰的语法,因为看起来可读性是它的主要目标之一 . 我不能强调这是多么重要,因为大多数开发人员会花时间阅读和维护现有代码,而不是创建代码 .
另一个好处是接口和实现类以相同的方式处理,与EasyMock不同,您仍然需要记住(并检查)使用EasyMock类扩展 .
我最近快速浏览了JMockit,虽然功能的清单非常全面,但我认为这样做的代价是结果代码的易读性,并且必须写更多内容 .
对我来说,Mockito打出了最佳点,易于编写和阅读,并处理大多数代码需要的大多数情况 . 使用Mockito和PowerMock将是我的选择 .
需要考虑的一件事是,如果您自己开发,或者在一个小型的紧密团队中进行开发,您可能选择的工具对于拥有不同技能水平的开发人员的大型公司来说可能不是最佳选择 . 在后一种情况下,需要更多考虑可读性,易用性和简单性 . 如果很多人最终没有使用它或者不维护测试,那么获得最终的模拟框架是没有意义的 .
我们在工作中大量使用EasyMock和EasyMock类扩展,并对它非常满意 . 它基本上为您提供所需的一切 . 看看文档,有一个很好的例子,它向您展示了EasyMock的所有功能 .
我很早就使用了JMock . 我在上一个项目中尝试过Mockito并且喜欢它 . 更简洁,更清洁 . PowerMock涵盖了Mockito中不存在的所有需求,例如模拟静态代码,模拟实例创建,模拟最终类和方法 . 所以我需要完成我的工作 .
我喜欢JMock因为你能够设定期望 . 这与检查某些模拟库中是否调用了一个方法完全不同 . 使用JMock,您可以编写非常复杂的期望 . 见jmock cheat-sheat .
是的,Mockito是一个很棒的框架 . 我与hamcrest和Google guice一起使用它来设置我的测试 .
模拟的最佳解决方案是让机器使用基于规范的自动化测试完成所有工作 . 对于Java,请参阅ScalaCheck和Functional Java库中包含的Reductio框架 . 使用基于规范的自动化测试框架,您可以提供该方法的规范在测试中(关于它的属性应该是真的)并且框架自动生成测试以及模拟对象 .
例如,以下属性测试Math.sqrt方法,以查看任何正数n平方的平方根是否等于n .
val propSqrt = forAll { (n: Int) => (n >= 0) ==> scala.Math.sqrt(n*n) == n }
当您调用 propSqrt.check() 时,ScalaCheck会生成数百个整数并检查每个整数的属性,同时自动确保边缘情况得到很好的覆盖 .
propSqrt.check()
尽管ScalaCheck是用Scala编写的,并且需要Scala编译器,但使用它可以很容易地测试Java代码 . Functional Java中的Reductio框架是相同概念的纯Java实现 .
Mockito还提供了存根方法,匹配参数(如anyInt()和anyString()),验证调用次数(times(3),atLeastOnce(),never()),and more的选项 .
我还发现Mockito是simple and clean .
我不喜欢Mockito的一件事是你can't stub static methods .
对于稍微不同的东西,您可以使用JRuby和Mocha这些组合在JtestR中,以富有表现力和简洁的Ruby为您的Java代码编写测试 . JtestR here有一些有用的模拟示例 . 这种方法的一个优点是模拟具体类非常简单 .
我开始通过JMock使用模拟,但最终转换为使用EasyMock . EasyMock就是这样, - 更轻松 - 并提供了一种感觉更自然的语法 . 从那以后我没有换过 .
14 回答
我使用Mockito取得了很大的成功 .
当我尝试学习JMock和EasyMock时,我发现学习曲线有点陡峭(尽管可能只是我) .
我喜欢Mockito,因为它简单而干净的语法让我能够很快掌握 . 最小的语法旨在很好地支持常见的情况,虽然我需要做一些更复杂的事情我发现我想要的东西是支持和易于掌握的 .
这是Mockito主页上的一个(删节)示例:
它没有那么简单 .
我能想到的唯一主要缺点是它不会模拟静态方法 .
我是PowerMock的创造者,所以显然我必须推荐它! :-)
PowerMock扩展了EasyMock和Mockito,具有mock static methods,最终甚至私有方法的能力 . EasyMock支持已经完成,但Mockito插件需要更多工作 . 我们还计划添加JMock支持 .
PowerMock并不打算替换其他框架,而是可以在其他框架不允许模拟的棘手情况下使用它 . PowerMock还包含其他有用的功能,例如suppressing static initializers和构造函数 .
JMockit project site包含大量当前模拟工具包的比较信息 .
特别是,请查看 feature comparison matrix ,其中包括EasyMock,jMock,Mockito,Unitils Mock,PowerMock,当然还有JMockit . 我尽可能地保持其准确和最新 .
我一直在JMockit取得成功 .
它有点原始且记录不足 . 它使用ASM动态重新定义类字节码,因此它可以模拟所有方法,包括静态,私有,构造函数和静态初始化器 . 例如:
它有一个Expectations界面,允许记录/播放场景:
缺点是它需要Java 5/6 .
您还可以使用Groovy查看测试 . 在Groovy中,您可以使用'as'运算符轻松模拟Java接口:
除了这个基本功能外,Groovy还提供了更多关于模拟前端的功能,包括强大的
MockFor
和StubFor
类 .http://docs.codehaus.org/display/GROOVY/Groovy+Mocks
我开始使用EasyMock模拟 . 很容易理解,但重播步骤有点烦人 . Mockito删除了它,也有一个更清晰的语法,因为看起来可读性是它的主要目标之一 . 我不能强调这是多么重要,因为大多数开发人员会花时间阅读和维护现有代码,而不是创建代码 .
另一个好处是接口和实现类以相同的方式处理,与EasyMock不同,您仍然需要记住(并检查)使用EasyMock类扩展 .
我最近快速浏览了JMockit,虽然功能的清单非常全面,但我认为这样做的代价是结果代码的易读性,并且必须写更多内容 .
对我来说,Mockito打出了最佳点,易于编写和阅读,并处理大多数代码需要的大多数情况 . 使用Mockito和PowerMock将是我的选择 .
需要考虑的一件事是,如果您自己开发,或者在一个小型的紧密团队中进行开发,您可能选择的工具对于拥有不同技能水平的开发人员的大型公司来说可能不是最佳选择 . 在后一种情况下,需要更多考虑可读性,易用性和简单性 . 如果很多人最终没有使用它或者不维护测试,那么获得最终的模拟框架是没有意义的 .
我们在工作中大量使用EasyMock和EasyMock类扩展,并对它非常满意 . 它基本上为您提供所需的一切 . 看看文档,有一个很好的例子,它向您展示了EasyMock的所有功能 .
我很早就使用了JMock . 我在上一个项目中尝试过Mockito并且喜欢它 . 更简洁,更清洁 . PowerMock涵盖了Mockito中不存在的所有需求,例如模拟静态代码,模拟实例创建,模拟最终类和方法 . 所以我需要完成我的工作 .
我喜欢JMock因为你能够设定期望 . 这与检查某些模拟库中是否调用了一个方法完全不同 . 使用JMock,您可以编写非常复杂的期望 . 见jmock cheat-sheat .
是的,Mockito是一个很棒的框架 . 我与hamcrest和Google guice一起使用它来设置我的测试 .
模拟的最佳解决方案是让机器使用基于规范的自动化测试完成所有工作 . 对于Java,请参阅ScalaCheck和Functional Java库中包含的Reductio框架 . 使用基于规范的自动化测试框架,您可以提供该方法的规范在测试中(关于它的属性应该是真的)并且框架自动生成测试以及模拟对象 .
例如,以下属性测试Math.sqrt方法,以查看任何正数n平方的平方根是否等于n .
当您调用
propSqrt.check()
时,ScalaCheck会生成数百个整数并检查每个整数的属性,同时自动确保边缘情况得到很好的覆盖 .尽管ScalaCheck是用Scala编写的,并且需要Scala编译器,但使用它可以很容易地测试Java代码 . Functional Java中的Reductio框架是相同概念的纯Java实现 .
Mockito还提供了存根方法,匹配参数(如anyInt()和anyString()),验证调用次数(times(3),atLeastOnce(),never()),and more的选项 .
我还发现Mockito是simple and clean .
我不喜欢Mockito的一件事是你can't stub static methods .
对于稍微不同的东西,您可以使用JRuby和Mocha这些组合在JtestR中,以富有表现力和简洁的Ruby为您的Java代码编写测试 . JtestR here有一些有用的模拟示例 . 这种方法的一个优点是模拟具体类非常简单 .
我开始通过JMock使用模拟,但最终转换为使用EasyMock . EasyMock就是这样, - 更轻松 - 并提供了一种感觉更自然的语法 . 从那以后我没有换过 .