121 java unit-testing jmockit mocking mockito
我正在调查哪个模拟框架用于我的项目,并将其缩小到JMockit和Mockito.
我注意到Mockito在Stackoverflow上被评为" Java最好的模拟框架 ".
在比较JMockit的" Mocking Tool Comparision Matrix "的功能时,似乎JMockit具有多种不同的功能.
有没有人有任何关于Mockito可以用JMockit无法实现的具体信息(不是意见),反之亦然?
Hen*_*wan 137
我说比赛是在JMockit和PowerMock之间,然后是Mockito.
我会留下"普通"的jMock和EasyMock,因为它们只使用代理和CGLIB,并且不像新的框架那样使用Java 5工具.
jMock也没有超过4年的稳定版本.jMock 2.6.0从RC1到RC2需要2年,然后在实际发布之前需要2年.
关于Proxy&CGLIB vs instrumentation:
(EasyMock和jMock)基于java.lang.reflect.Proxy,它需要实现一个接口.此外,它们支持通过CGLIB子类生成为类创建模拟对象.因此,所述类不能是最终的,只能模拟可覆盖的实例方法.但最重要的是,在使用这些工具时,测试代码的依赖关系(即,测试中给定类所依赖的其他类的对象)必须由测试控制,以便可以将模拟实例传递给客户端那些依赖.因此,依赖关系不能简单地使用我们想要编写单元测试的客户端类中的new运算符进行实例化.
最终,传统模拟工具的技术限制对生产代码施加了以下设计限制:
- 可能需要在测试中模拟的每个类必须实现单独的接口或不是最终的.
- 要测试的每个类的依赖关系必须通过可配置的实例创建方法(工厂或服务定位器)获得,或者暴露用于依赖注入.否则,单元测试将无法将依赖项的模拟实现传递给被测单元.
- 由于只能模拟实例方法,因此要进行单元测试的类不能在其依赖项上调用任何静态方法,也不能使用任何构造函数对它们进行实例化.
以上内容复制自http://jmockit.org/about.html.此外,它在几个方面比较了它自己(JMockit),PowerMock和Mockito:
现在有其他Java的模拟工具,它们也克服了传统的限制,包括PowerMock,jEasyTest和MockInject.最接近JMockit功能集的是PowerMock,因此我将在此简要评估它(此外,其他两个更受限制,似乎不再积极开发).
JMockit与PowerMock
- 首先,PowerMock不提供完整的模拟API,而是作为另一个工具的扩展,目前可以是EasyMock或Mockito.对于这些工具的现有用户来说,这显然是一个优势.
- 另一方面,JMockit提供了全新的API,尽管它的主要API(Expectations)类似于EasyMock和jMock.虽然这会创建更长的学习曲线,但它也允许JMockit提供更简单,更一致且更易于使用的API.
- 与JMockit Expectations API相比,PowerMock API更"低级",迫使用户弄清楚并指定需要准备哪些类进行测试(使用@PrepareForTest({ClassA.class,...})注释并且需要特定的API调用来处理生产代码中可能存在的各种语言结构:静态方法(mockStatic(ClassA.class)),构造函数(suppress(constructor(ClassXyz.class))),构造函数调用( expectNew(AClass.class)),部分模拟(createPartialMock(ClassX.class,"methodToMock"))等.
- 使用JMockit Expectations,所有类型的方法和构造函数都以纯粹的声明方式进行模拟,通过@Mocked注释中的正则表达式指定部分模拟,或者简单地"取消模拟"没有记录期望的成员; 也就是说,开发人员只是为测试类声明一些共享的"模拟字段",或者为单个测试方法声明一些"本地模拟字段"和/或"模拟参数"(在最后一种情况下,@Mocked注释通常不会被需要).
- 目前,PowerMock不支持JMockit中可用的一些功能,例如支持模拟equals和hashCode,重写方法等.此外,没有相当于JMockit能够在测试执行时捕获实例和模拟指定基类型的实现,而测试代码本身并不了解实际的实现类.
- PowerMock使用自定义类加载器(通常每个测试类一个),以生成模拟类的修改版本.如此大量使用自定义类加载器可能会导致与第三方库发生冲突,因此有时需要在测试类上使用@PowerMockIgnore("package.to.be.ignored")注释.
- JMockit使用的机制(通过"Java代理"运行时检测)更简单,更安全,尽管在JDK 1.5上进行开发时需要将"-javaagent"参数传递给JVM; 在JDK 1.6+(可以始终用于开发,即使在旧版本上部署)也没有这样的要求,因为JMockit可以使用Attach API按需透明地加载Java代理.
另一个最近的嘲弄工具是Mockito.虽然它并没有试图克服旧工具(jMock,EasyMock)的限制,但它确实引入了一种新的行为测试模式.JMockit还通过Verifications API支持这种替代风格.
JMockit vs Mockito
- Mockito依赖于对其API的显式调用,以便在记录(何时(...))和验证(验证(...))阶段之间分离代码.这意味着在测试代码中对模拟对象的任何调用也需要调用模拟API.此外,这通常会在(...)和验证(模拟)...调用时导致重复.
- 使用JMockit,不存在类似的调用.当然,我们有新的NonStrictExpectations()和新的Verifications()构造函数调用,但它们每次测试只发生一次(通常),并且完全独立于对模拟方法和构造函数的调用.
- Mockito API包含用于调用模拟方法的语法中的几个不一致.在记录阶段,我们调用像when(mock.mockedMethod(args))...在验证阶段,这个相同的调用将被写为verify(mock).mockedMethod(args).请注意,在第一种情况下,对mockedMethod的调用直接在模拟对象上进行,而在第二种情况下,它是在verify(mock)返回的对象上进行的.
- JMockit没有这种不一致性,因为对模拟方法的调用总是直接在模拟实例本身上进行.(仅有一个例外:为了匹配同一个模拟实例上的调用,使用onInstance(模拟)调用,产生类似onInstance(mock).mockedMethod(args)的代码;但大多数测试不需要使用它. )
- 就像其他依赖方法链接/包装的模拟工具一样,Mockito在存在void方法时也会遇到不一致的语法.例如,你写时(mockedList.get(1)).thenThrow(new RuntimeException()); 对于非void方法,和doThrow(new RuntimeException()).when(mockedList).clear(); 一个无效的.使用JMockit,它总是使用相同的语法:mockedList.clear(); result = new RuntimeException();.
- 使用Mockito间谍时又出现了另一种不一致:"模拟"允许在间谍实例上执行真正的方法.例如,如果spy引用了一个空List,那么代替写入(spy.get(0)).thenReturn("foo"),你需要编写doReturn("foo").when(spy).get( 0).使用JMockit,动态模拟功能提供与间谍类似的功能,但没有此问题,因为实际方法仅在重放阶段执行.
- 在EasyMock和jMock中,Java的第一个模拟API,重点完全在于记录模拟对象的预期调用,对于(默认情况下)不允许意外调用的模拟对象.这些API还提供了允许对允许意外调用的模拟对象进行允许调用的记录,但这被视为第二类功能.此外,使用这些工具,在执行测试代码后,无法显式验证对模拟的调用.所有这些验证都是隐式和自动执行的.
- 在Mockito(以及Unitils Mock)中,采取了相反的观点.对测试期间可能发生的模拟对象的所有调用(无论是否记录)都是允许的,从未预料到.在执行测试代码后,将显式执行验证,而不是自动执行.
- 两种方法都过于极端,因此不是最优的.JMockit Expectations&Verifications是唯一允许开发人员为每个测试无缝选择严格(默认情况下预期)和非严格(默认情况下允许)模拟调用的最佳组合的API.
- 更明确的是,Mockito API具有以下缺点.如果您需要验证在测试期间是否发生了对非void模拟方法的调用,但测试需要该方法的返回值与返回类型的默认值不同,那么Mockito测试将具有重复的代码: a when(mock.someMethod()).thenReturn(xyz)在记录阶段调用,并在验证阶段验证(模拟).someMethod().使用JMockit,可以始终记录严格的期望,无需明确验证.或者,可以为任何记录的非严格期望指定调用计数约束(times = 1)(使用Mockito,这样的约束只能在verify(模拟,约束)调用中指定).
- Mockito的顺序验证语法很差,并且对于完整的验证(即,检查是否明确验证了对模拟对象的所有调用).在第一种情况下,需要创建一个额外的对象,并调用对其进行验证:InOrder inOrder = inOrder(mock1,mock2,...).在第二种情况下,需要进行诸如verifyNoMoreInteractions(mock)或verifyZeroInteractions(mock1,mock2)之类的调用.
- 使用JMockit,您只需编写新的VerificationsInOrder()或新的FullVerifications()而不是新的Verifications()(或新的FullVerificationsInOrder()来组合这两个要求).无需指定涉及哪些模拟对象.没有额外的模拟API调用.作为奖励,通过在有序验证块中调用unverifiedInvocations(),您可以执行在Mockito中根本无法进行的与订单相关的验证.
最后,JMockit Testing Toolkit具有比其他模拟工具包更广泛的范围和更宏伟的目标,以提供完整而复杂的开发人员测试解决方案.即使没有人为限制,一个很好的模拟API也不足以高效地创建测试.与IDE无关,易于使用且集成良好的代码覆盖率工具也是必不可少的,这就是JMockit Coverage旨在提供的功能.随着测试套件规模的扩大,开发人员测试工具集的另一部分将变得更加有用,它能够在对生产代码进行本地化更改后逐步重新运行测试.这也包含在Coverage工具中.
(授予,来源可能有偏见,但很好......)
我会说和JMockit一起去.它是最容易使用,最灵活的,几乎适用于所有情况甚至是困难的情况和场景,当你无法控制要测试的类时(或者由于兼容性原因你不能打破它).
我对JMockit的经历非常积极.
Tum*_*mer 23
我和Mockito以及JMockit一起工作,我的经验是:
的Mockito:
EasyMock的:
JMockit:
此外,JMockit的其他好处:
我个人更喜欢JMockit,我认为它更丰富,更灵活,但需要更加陡峭的学习曲线.通常有多种方法可以实现相同的模拟效果,并且在设计模拟时需要更多的注意.
| 归档时间: |
|
| 查看次数: |
62908 次 |
| 最近记录: |