Answers:
我使用Mockito取得了成功。
当我尝试学习JMock和EasyMock时,我发现学习曲线有些陡峭(尽管可能仅仅是我一个人)。
我喜欢Mockito,因为它的语法简洁明了,我很快就能掌握。最小的语法旨在很好地支持常见情况,尽管几次我需要做一些更复杂的事情,但我发现我想要的东西是受支持的并且易于理解。
这是Mockito主页上的一个(简短的)示例:
import static org.mockito.Mockito.*;
List mockedList = mock(List.class);
mockedList.clear();
verify(mockedList).clear();
没有比这更简单的了。
我能想到的唯一主要缺点是,它不会模拟静态方法。
我是PowerMock的创建者,因此显然我必须建议这样做!:-)
PowerMock扩展了EasyMock和Mockito的功能,可以模拟静态方法,最终方法甚至私有方法。EasyMock支持已完成,但Mockito插件需要更多工作。我们还计划添加JMock支持。
PowerMock并不是要替换其他框架,而是可以在其他框架不允许模拟的棘手情况下使用。PowerMock还包含其他有用的功能,例如禁止使用静态初始化程序和构造函数。
该JMockit项目网站包含了大量的信息,比较当前的嘲弄工具包。
特别是,请查看功能比较矩阵,其中包括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
类。
我开始在EasyMock中使用模拟。很容易理解,但是重播步骤有点烦人。Mockito删除了此内容,并且语法更简洁,因为看起来可读性是其主要目标之一。我没有足够强调它的重要性,因为大多数开发人员将花费时间阅读和维护现有代码,而不是创建代码。
另一件事是,接口和实现类以相同的方式处理,与EasyMock不同,在EasyMock中,您仍然需要记住(并检查)以使用EasyMock类扩展。
最近,我快速浏览了JMockit,尽管功能清单很全面,但我认为这样做的代价是所生成代码的可读性,并且必须编写更多代码。
对我而言,Mockito达到了最理想的位置,易于编写和阅读,并且可以处理大多数代码所需的大多数情况。与PowerMock一起使用Mockito是我的选择。
要考虑的一件事是,如果您是自己开发的,或者是在紧密的小型团队中开发的,那么对于拥有不同技能水平的开发人员的大型公司而言,它可能不是最佳选择。在后一种情况下,需要更多考虑可读性,易用性和简单性。如果很多人最终不使用它或不维护测试,那么获得最终的模拟框架毫无意义。
我喜欢JMock,因为您能够设定期望。这与检查是否在某些模拟库中找到了一种方法完全不同。使用JMock可以编写非常复杂的期望。见假装骗子。
是的,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会生成数百个整数并检查每个整数的属性,还可以自动确保边缘情况被正确覆盖。
尽管ScalaCheck是用Scala编写的,并且需要Scala编译器,但使用它测试Java代码还是很容易的。Functional Java中的Reductio框架是相同概念的纯Java实现。
Mockito还提供存根方法,匹配参数(如anyInt()和anyString()),验证调用次数(times(3),atLeastOnce(),never())等选项。
我还发现Mockito 简单干净。
我不喜欢Mockito的一件事是您不能对静态方法进行存根。
我开始通过JMock使用模拟,但最终过渡为使用EasyMock。EasyMock就是这样,更加轻松,并且提供了一种更加自然的语法。从那以后我再也没有切换。