Mockito与JMockit之间的比较 - 为什么Mockito投票比JMockit更好? [英] Comparison between Mockito vs JMockit - why is Mockito voted better than JMockit?

查看:3072
本文介绍了Mockito与JMockit之间的比较 - 为什么Mockito投票比JMockit更好?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在调查哪个模拟框架用于我的项目,并将其缩小到 JMockit Mockito

I'm investigating which mocking framework to use for my project and have narrowed it down to JMockit and Mockito.

我注意到 Mockito 被投票最好的Java模拟框架在Stackoverflow上。

比较 JMockit 上的功能模拟工具比较矩阵似乎 JMockit 有多种不同的功能。

I notice that Mockito was voted "the best mock framework for Java" on Stackoverflow.
In comparing features on JMockit's "Mocking Tool Comparision Matrix" it appears that JMockit has multiple different features.

有没有人对 Mockito 可以做的事情有任何特定的信息(不是意见),这是 JMockit ,反之亦然?

Does anyone have any specific information (not opinions) on what Mockito can do which can't be achieved with JMockit and vice versa?

推荐答案

我说比赛是在 JMockit PowerMock 之间进行的,然后 Mockito

I'd say the competition is between JMockit and PowerMock, then Mockito.

我会留下普通jMock和EasyMock,因为他们只使用代理& CGLIB并不像新的框架那样使用Java 5工具。

I'd leave "plain" jMock and EasyMock because they use only proxy & CGLIB and do not use Java 5 instrumentation like the newer frameworks.

jMock也没有超过4年的稳定版本。 jMock 2.6.0从RC1到RC2需要2年,然后在实际发布之前需要2年。

jMock also didn't have a stable release for over 4 years. jMock 2.6.0 required 2 years to go from RC1 to RC2, and then another 2 years before it actually got released.

关于Proxy& CGLIB vs instrumentation:

Regarding Proxy & CGLIB vs instrumentation:


(EasyMock和jMock)基于java.lang.reflect.Proxy,
需要一个接口实施
。另外,
支持通过CGLIB子类
generation为类创建模拟对象
。因此,所说的
类不能是最终的,只有
可覆盖的实例方法可以被
模拟。然而,最重要的是,当使用这些工具时,
是测试中代码的
依赖项(
是,
上的其他类的对象,测试中的给定类
depends)必须由
测试控制,以便模拟实例可以是
传递给那些
依赖项的客户端。因此,依赖性
不能简单地在客户端类中使用
new运算符实例化
,我们要编写单元测试。

(EasyMock and jMock) are based on java.lang.reflect.Proxy, which requires an interface to be implemented. Additionally, they support the creation of mock objects for classes through CGLIB subclass generation. Because of that, said classes cannot be final and only overridable instance methods can be mocked. Most importantly, however, when using these tools the dependencies of code under test (that is, the objects of other classes on which a given class under test depends) must be controlled by the tests, so that mock instances can be passed to the clients of those dependencies. Therefore, dependencies can't simply be instantiated with the new operator in a client class for which we want to write unit tests.

最终,传统模拟工具的技术限制

生产代码施加以下设计限制

Ultimately, the technical limitations of conventional mocking tools impose the following design restrictions on production code:


  1. 在测试中可能需要模拟的每个类必须实现
    a单独的接口或不是最终的。

  2. 每个要测试的类的依赖关系必须要么通过可配置的实例创建
    方法(工厂或服务
    定位器)获得
    ,要么接受
    注入依赖。否则,单元测试不会
    能够在
    test下将模拟实现
    的依赖项传递给单元。

  3. 因为只有实例方法可以模拟,要进行单元测试的类
    不能在
    上调用任何静态方法它们的依赖项,也不能使用任何构造函数实例化
    它们。


上述内容复制自 http:// jmockit.org/about.html 。此外,它在几个方面比较了它自己(JMockit),PowerMock和Mockito:

The above is copied from http://jmockit.org/about.html . Further, it compares between itself (JMockit), PowerMock, and Mockito in several ways:


现在还有其他的$ b $模拟工具b Java也克服了传统的
限制,它们之间是
PowerMock,jEasyTest和
MockInject。最接近
到JMockit功能集的是
PowerMock,所以我将在这里简要评估
(此外,另外两个是
更有限而且不是似乎是
积极开发了。)

There are now other mocking tools for Java which also overcome the limitations of the conventional ones, between them PowerMock, jEasyTest, and MockInject. The one that comes closest to the feature set of JMockit is PowerMock, so I will briefly evaluate it here (besides, the other two are more limited and don't seem to be actively developed anymore).


  • 首先,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(构造函数(ClassXyz.class))),
    构造函数调用
    (expectNew(AClass.class)),部分
    模拟(createPartialMock(ClassX.class,
    methodToMock))等等。

  • 使用JMockit Expectations,各种方法和构造函数都是纯粹以声明方式模拟的

    with part通过@Mocked
    注释中的
    正则表达式指定的ial mocking,或简单地un-mocking
    成员没有记录
    预期;也就是说,开发人员
    只是为测试类声明一些共享的mock
    字段,或者为个人声明一些
    本地模拟字段和/或模拟
    参数测试
    方法(在最后一种情况下,
    @Mocked注释通常不需要
    )。

  • JMockit中可用的一些功能,例如因为支持模拟
    等于和hashCode,重写
    方法,以及其他方法,目前在PowerMock中不支持
    。此外,有
    不等于JMockit能够获得
    捕获实例并且在测试执行时模拟指定基本
    类型的
    实现,而没有
    测试代码本身具有任何
    实际实现
    类的知识。

  • PowerMock使用自定义类加载器(通常每个测试类一个)
    以生成修改版本
    模拟类。如此大量使用
    的自定义类加载器可能导致与第三方库的
    冲突,
    因此需要有时使用
    @PowerMockIgnore(package.to.be。忽略)测试类上的
    注释。

  • JMockit使用的机制(运行时检测通过
    Java代理)更简单,更安全,
    虽然它确实需要在
    开发JDK 1.5时将
    -javaagent参数传递给JVM;在JDK 1.6+
    (可以随时用于
    开发,即使部署在
    旧版本上)也没有这样的
    要求,因为JMockit可以
    使用Attach API透明地在
    需求上加载Java代理。

  • First of all, PowerMock does not provide a complete API for mocking, but instead works as an extension to another tool, which currently can be EasyMock or Mockito. This is obviously an advantage for existing users of those tools.
  • JMockit, on the other hand, provides entirely new APIs, although its main API (Expectations) is similar to both EasyMock and jMock. While this creates a longer learning curve, it also allows JMockit to provide a simpler, more consistent, and easier to use API.
  • Compared to the JMockit Expectations API, the PowerMock API is more "low-level", forcing users to figure out and specify which classes need to be prepared for testing (with the @PrepareForTest({ClassA.class, ...}) annotation) and requiring specific API calls to deal with various kinds of language constructs that may be present in the production code: static methods (mockStatic(ClassA.class)), constructors (suppress(constructor(ClassXyz.class))), constructor invocations (expectNew(AClass.class)), partial mocks (createPartialMock(ClassX.class, "methodToMock")), etc.
  • With JMockit Expectations, all kinds of methods and constructors are mocked in a purely declarative way, with partial mocking specified through regular expressions in the @Mocked annotation or by simply "un-mocking" the members with no recorded expectations; that is, the developer simply declares some shared "mock fields" for the test class, or some "local mock fields" and/or "mock parameters" for individual test methods (and in this last case the @Mocked annotation often won't be needed).
  • Some capabilities available in JMockit, such as support for mocking equals and hashCode, overridden methods, and others, are currently not supported in PowerMock. Also, there is no equivalent to JMockit's ability to capture instances and mock implementations of specified base types as the test executes, without the test code itself having any knowledge of the actual implementation classes.
  • PowerMock uses custom class loaders (usually one per test class) in order to generate modified versions of the mocked classes. Such heavy use of custom class loaders can lead to conflicts with third-party libraries, hence the need to sometimes use the @PowerMockIgnore("package.to.be.ignored") annotation on test classes.
  • The mechanism used by JMockit (runtime instrumentation through a "Java agent") is simpler and safer, although it does require passing a "-javaagent" parameter to the JVM when developing on JDK 1.5; on JDK 1.6+ (which can always be used for development, even if deploying on an older version) there is no such requirement, since JMockit can transparently load the Java agent on demand by using the Attach API.

另一个最近的模拟工具是
Mockito 。虽然它没有尝试
来克服旧的
工具(jMock,EasyMock)的限制,但是它确实用
引入了一种新的行为方式
测试模拟。 JMockit还
支持这种替代风格,
通过Verifications API。

Another recent mocking tool is Mockito. Although it does not attempt to overcome the limitations of older tools (jMock, EasyMock), it does introduce a new style of behavior testing with mocks. JMockit also supports this alternative style, through the Verifications API.


  • Mockito依赖于对其API的显式调用,以便在记录(当(...))和
    验证(验证(...)之间分隔代码
    ))阶段。这个
    意味着对测试代码中的模拟
    对象的任何调用也需要
    调用模拟API。
    此外,当(...)和
    验证(模拟)...来电时,这通常会导致
    重复。

  • 使用JMockit,没有类似的电话。当然,我们有新的
    NonStrictExpectations()和新的
    Verifications()构造函数调用,但
    它们每个测试只发生一次
    (通常),并且完全是

    模拟方法和构造函数的调用分开。

  • Mockito API包含用于对模拟方法进行
    调用的语法中的几个不一致。在
    记录阶段,我们有
    之类的调用(mock.mockedMethod(args))...而在验证阶段的
    同样的调用
    将被写为
    验证(mock).mockedMethod(args)。
    请注意,在第一种情况下,对mockedMethod的
    调用直接在模拟对象上进行
    ,而在
    中,第二种情况是在返回的
    对象上进行的通过验证(模拟)。

  • JMockit没有这种不一致性,因为对
    模拟方法的调用总是直接在模拟实例
    本身上进行
    。 (只有一个例外:
    来匹配同一个
    模拟实例的调用,使用onInstance(模拟)
    调用,产生代码,如
    onInstance(mock).mockedMethod (args);
    大多数测试都不需要使用它,但是
    虽然。)

  • 就像其他依赖方法
    链接的模拟工具一样/ wrap,当存在
    void方法时,Mockito还运行
    到不一致的语法。例如,当写(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&验证
    是唯一允许
    开发人员无缝选择
    最佳严格组合(默认为
    )和非严格组合(由
    默认允许)的API )每个
    测试的模拟调用。

  • 为了更清楚,Mockito API有以下缺点。如果
    需要验证在
    测试期间是否发生了对
    非void模拟方法的调用,但测试需要从该方法返回
    返回值
    不同于
    返回类型的默认值,那么Mockito测试
    将有重复的代码:a
    when(mock.someMethod())。thenReturn(xyz)
    在记录阶段调用,并在
    验证阶段验证(模拟).someMethod()
    。使用JMockit,可以始终记录严格的
    预期,
    ,无需明确
    验证。或者,对于任何记录的非严格
    预期,调用
    计数约束(times = 1)可以是
    (对于Mockito,这样的
    约束只能在$ b中指定$ b验证(模拟,约束)调用)。

  • Mockito的顺序验证语法很差,并且完整的
    验证(即检查
    all对模拟对象的调用是
    显式验证)。在第一个
    的情况下,额外的对象需要创建
    ,并且调用验证在
    上进行:InOrder inOrder = inOrder(mock1,
    mock2,...) 。在第二种情况下,需要调用
    ,例如verifyNoMoreInteractions(mock)或
    verifyZeroInteractions(mock1,mock2)

  • 使用JMockit,你只需编写新的VerificationsInOrder()或新的
    FullVerifications()而不是新的
    Verifications()(或新的
    FullVerificationsInOrder()来组合
    两个要求)。无需指定涉及模拟对象的
    。没有
    额外的模拟API调用。并且作为
    奖金,通过在
    订购的验证区块内调用
    unverifiedInvocations(),您可以
    执行与Mockito无关的订单相关验证

  • Mockito relies on explicit calls to its API in order to separate code between the record (when(...)) and verify (verify(...)) phases. This means that any invocation to a mock object in test code will also require a call to the mocking API. Additionally, this will often lead to repetitive when(...) and verify(mock)... calls.
  • With JMockit, no similar calls exist. Sure, we have the new NonStrictExpectations() and new Verifications() constructor calls, but they occur only once per test (typically), and are completely separate from the invocations to mocked methods and constructors.
  • The Mockito API contains several inconsistencies in the syntax used for invocations to mocked methods. In the record phase, we have calls like when(mock.mockedMethod(args))... while in the verify phase this same call will be written as verify(mock).mockedMethod(args). Notice that in the first case the invocation to mockedMethod is made directly on the mock object, while in the second case it is made on the object returned by verify(mock).
  • JMockit has no such inconsistencies because invocations to mocked methods are always made directly on the mocked instances themselves. (With one exception only: to match invocations on the same mocked instance, an onInstance(mock) call is used, resulting in code like onInstance(mock).mockedMethod(args); most tests won't need to use this, though.)
  • Just like other mocking tools which rely on method chaining/wrapping, Mockito also runs into inconsistent syntax when stubbing void methods. For example, you write when(mockedList.get(1)).thenThrow(new RuntimeException()); for a non-void method, and doThrow(new RuntimeException()).when(mockedList).clear(); for a void one. With JMockit, it's always the same syntax: mockedList.clear(); result = new RuntimeException();.
  • Yet another inconsistency occurs in the use of Mockito spies: "mocks" that allow the real methods to be executed on the spied instance. For example, if spy refers to an empty List, then instead of writing when(spy.get(0)).thenReturn("foo") you will need to write doReturn("foo").when(spy).get(0). With JMockit, the dynamic mocking feature provides similar functionality to spies, but without this issue since real methods only get executed during the replay phase.
  • In EasyMock and jMock, the first mocking APIs for Java, the focus was entirely on the recording of expected invocations of mocked methods, for mock objects that (by default) do not allow unexpected invocations. Those APIs also provide the recording of allowed invocations for mock objects that do allow unexpected invocations, but this was treated as a second-class feature. Additionally, with these tools there is no way to explicitly verify invocations to mocks after the code under test is exercised. All such verifications are performed implicitly and automatically.
  • In Mockito (and also in Unitils Mock), the opposite viewpoint is taken. All invocations to mock objects that may happen during the test, whether recorded or not, are allowed, never expected. Verification is performed explicitly after the code under test is exercised, never automatically.
  • Both approaches are too extreme, and consequently less than optimal. JMockit Expectations & Verifications is the only API that allows the developer to seamlessly choose the best combination of strict (expected by default) and non-strict (allowed by default) mock invocations for each test.
  • To be more clear, the Mockito API has the following shortcoming. If you need to verify that an invocation to a non-void mocked method happened during the test, but the test requires a return value from that method that is different from the default for the return type, then the Mockito test will have duplicate code: a when(mock.someMethod()).thenReturn(xyz) call in the record phase, and a verify(mock).someMethod() in the verify phase. With JMockit, a strict expectation can always be recorded, which won't have to be explicitly verified. Alternatively, an invocation count constraint (times = 1) can be specified for any recorded non-strict expectation (with Mockito such constraints can only be specified in a verify(mock, constraint) call).
  • Mockito has poor syntax for verifications in order, and for full verifications (that is, checking that all invocations to mock objects are explicitly verified). In the first case, an extra object needs to be created, and calls to verify made on it: InOrder inOrder = inOrder(mock1, mock2, ...). In the second case, calls like verifyNoMoreInteractions(mock) or verifyZeroInteractions(mock1, mock2) need to be made.
  • With JMockit, you simply write new VerificationsInOrder() or new FullVerifications() instead of new Verifications() (or new FullVerificationsInOrder() to combine both requirements). No need to specify which mock objects are involved. No extra mocking API calls. And as a bonus, by calling unverifiedInvocations() inside an ordered verification block, you can perform order-related verifications that are simply impossible in Mockito.

最后,JMockit Testing Toolkit
有一个更宽的范围更有野心
目标
比其他模拟工具包,
为了提供一个完整且
的复杂开发人员测试
解决方案。一个很好的模拟API,即使是没有人为限制的
,也不足以生成
测试。 IDE不可知,易于使用,
和完善的代码覆盖率工具
也是必不可少的,这就是JMockit Coverage旨在提供的

开发人员测试
工具集的另一部分随着测试套件的增长而变得更有用

在本地化更改后逐步重新运行测试
的能力生产
代码;这也包含在
Coverage工具中。

Finally, the JMockit Testing Toolkit has a wider scope and more ambitious goals than other mocking toolkits, in order to provide a complete and sophisticated developer testing solution. A good API for mocking, even without artificial limitations, is not enough for productive creation of tests. An IDE-agnostic, easy to use, and well integrated Code Coverage tool is also essential, and that's what JMockit Coverage aims to provide. Another piece of the developer testing toolset which will become more useful as the test suite grows in size is the ability to incrementally rerun tests after a localized change to production code; this is also included in the Coverage tool.

(授予,来源可能有偏见,但是...... )

(granted, the source may be biased, but well...)

我会说 JMockit 。它是最容易使用,最灵活的,几乎适用于所有情况,甚至是难以控制要测试的类的情况(或者由于兼容性原因而无法破解它)。

I'd say go with JMockit. It's the easiest to use, flexible, and works for pretty much all cases even difficult ones and scenarios when you can't control the class to be tested (or you can't break it due to compatibility reasons etc.).

我对JMockit的体验非常积极。

My experiences with JMockit have been very positive.

这篇关于Mockito与JMockit之间的比较 - 为什么Mockito投票比JMockit更好?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆