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