EasyMock vs Mockito:devise与可维护性?

考虑这个问题的一个方法是:如果我们关心代码的devise,那么EasyMock是更好的select,因为它通过它的期望的概念给你提供反馈。

如果我们关心testing的可维护性(比较容易阅读,编写,并且不会受到很大影响的脆弱testing),那么Mockito似乎是更好的select。

我的问题是:

  • 如果您在大型项目中使用EasyMock,您是否发现您的testing难以维护?
  • Mockito(Endotesting除外)的局限性是什么?

我是一个EasyMock开发者,所以有点偏,但是我已经在大型项目上使用了EasyMock。

我的观点是,EasyMocktesting确实会暂时中断一次。 EasyMock迫使你做一个你期望的完整logging。 这需要一些纪律。 你应该logging什么样的testing方法当前需要什么。 例如,如果一个方法在模拟上被调用了多less次并不重要,那么不要害怕使用和andStubReturn 。 另外,如果你不关心参数,可以使用anyObject()等。 在TDD的思考可以帮助。

我的分析是,EasyMocktesting会更频繁地打破,但Mockito的testing将不会当你想要他们。 我更喜欢我的testing打破。 至less我知道我的发展有什么影响。 这当然是我个人的观点。

我不会争论这些框架的testing可读性,大小或testing技术,我相信它们是平等的,但是通过一个简单的例子,我将向您展示这些差异。

鉴于:我们有一个类负责存储某个地方的东西:

 public class Service { public static final String PATH = "path"; public static final String NAME = "name"; public static final String CONTENT = "content"; private FileDao dao; public void doSomething() { dao.store(PATH, NAME, IOUtils.toInputStream(CONTENT)); } public void setDao(FileDao dao) { this.dao = dao; } } 

我们要testing它:

的Mockito:

 public class ServiceMockitoTest { private Service service; @Mock private FileDao dao; @Before public void setUp() { MockitoAnnotations.initMocks(this); service = new Service(); service.setDao(dao); } @Test public void testDoSomething() throws Exception { // given // when service.doSomething(); // then ArgumentCaptor<InputStream> captor = ArgumentCaptor.forClass(InputStream.class); Mockito.verify(dao, times(1)).store(eq(Service.PATH), eq(Service.NAME), captor.capture()); assertThat(Service.CONTENT, is(IOUtils.toString(captor.getValue()))); } } 

EasyMock的:

 public class ServiceEasyMockTest { private Service service; private FileDao dao; @Before public void setUp() { dao = EasyMock.createNiceMock(FileDao.class); service = new Service(); service.setDao(dao); } @Test public void testDoSomething() throws Exception { // given Capture<InputStream> captured = new Capture<InputStream>(); dao.store(eq(Service.PATH), eq(Service.NAME), capture(captured)); replay(dao); // when service.doSomething(); // then assertThat(Service.CONTENT, is(IOUtils.toString(captured.getValue()))); verify(dao); } } 

正如你所看到的,两个testing都是相同的,而且两者都通过了。 现在,让我们想象别人改变了服务实现并尝试运行testing。

新服务实施:

 dao.store(PATH + separator, NAME, IOUtils.toInputStream(CONTENT)); 

在PATH常数的末尾添加分隔符

testing结果如何现在看起来像? 首先,两个testing都会失败,但是会出现不同的错误消息:

EasyMock的:

 java.lang.AssertionError: Nothing captured yet at org.easymock.Capture.getValue(Capture.java:78) at ServiceEasyMockTest.testDoSomething(ServiceEasyMockTest.java:36) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 

的Mockito:

 Argument(s) are different! Wanted: dao.store( "path", "name", <Capturing argument> ); -> at ServiceMockitoTest.testDoSomething(ServiceMockitoTest.java:34) Actual invocation has different arguments: dao.store( "path\", "name", java.io.ByteArrayInputStream@1c99159 ); -> at Service.doSomething(Service.java:13) 

EasyMocktesting发生了什么,为什么结果没有被捕获? 商店的方法没有执行,但等一下,这是为什么EasyMock谎言给我们?

这是因为EasyMock将两个职责混合在一起 – 存根和validation。 这就是为什么当出现错误时很难理解哪个部分导致失败。

当然,你可以告诉我 – 只要改变testing,并在断言之前移动validation。 哇,你是认真的吗,开发者应该记住一些由嘲讽框架强制的魔法命令?

顺便说一句,它不会帮助:

 java.lang.AssertionError: Expectation failure on verify: store("path", "name", capture(Nothing captured yet)): expected: 1, actual: 0 at org.easymock.internal.MocksControl.verify(MocksControl.java:111) at org.easymock.classextension.EasyMock.verify(EasyMock.java:211) 

不过,它对我说,方法没有被执行,但它是,只有另一个参数。

为什么Mockito更好? 这个框架不会在一个地方混合两个职责,当你的testing失败的时候,你会很容易理解为什么。

如果我们关心代码的devise,那么Easymock是更好的select,因为它通过它的期望的概念给你提供反馈

有趣。 我发现“期望概念”使得许多开发者在testing中提出了越来越多的期望,只是为了满足意外的方法调用问题。 它如何影响devise?

当您更改代码时,testing不应该中断。 function停止工作时,testing应该中断。 如果有人喜欢testing破坏,当任何代码更改发生时,我build议写一个testing,断言Java文件的MD5校验和:)

我不认为你应该太在意这个。 Easymock和Mockito都可以configuration为'strict'或'nice',唯一的区别是默认情况下,Easymock是严格的,Mockito是很好的。

与所有testing一样,没有硬性规定,您需要平衡testing信心与可维护性。 我通常会发现,某些function或技术领域需要高度的信心,我会使用“严格”模拟。 例如,我们可能不希望debitAccount()方法被多次调用! 然而在其他情况下,模拟实际上只不过是一个存根,所以我们可以testing代码的真正“肉”。

在Mockito的生活初期,API兼容性是一个问题,但是现在有更多的工具支持这个框架。 Powermock(个人喜好)现在有一个mockito扩展

我更喜欢mockito诚实。 一直在使用EasyMock和单元,两者的结合往往会导致像IllegalArgumentExceptionexception:不是一个接口,以及MissingBehaviorExceptions。 在这两种情况下,尽pipe代码和testing代码都非常好。 看来MissingBehaviorException是由于使用createMock创build的模拟对象(使用classextentions !!)确实产生了这个错误。 当使用@Mock它确实工作! 我不喜欢这种误导性的行为,对我来说这是一个清楚的迹象,它的开发者不知道他们在做什么。 一个好的框架应该总是易于使用,不含糊。 IllegalArgumentException也是由于一些EasyMock内部的混合。 另外,录音不是我想要做的。 我想testing我的代码是否抛出exception,并返回预期的结果。 这与代码覆盖结合是我的正确工具。 我不希望我的testing中断,每当我把1行代码高于或低于前一个,因为这可以提高性能等。 随着mockito这是没有问题的。 使用EasyMock,即使代码没有被破坏,也会导致testing失败。 那很不好。 它花费时间,因此钱。 你想testing预期的行为。 你真的关心事情的顺序吗? 我想在极less数情况下你可能会。 然后使用Easymock。 在其他情况下,我认为使用mockito编写testing花费的时间要less得多。

亲切的问候劳伦斯