【问题标题】:Comparison between Mockito vs JMockit - why is Mockito voted better than JMockit? [closed]Mockito 与 JMockit 之间的比较 - 为什么 Mockito 的投票比 JMockit 好? [关闭]
【发布时间】:2011-05-05 13:42:07
【问题描述】:

我正在研究为我的项目使用哪个模拟框架,并将其范围缩小到JMockitMockito

我注意到 Mockito 在 Stackoverflow 上被选为“the best mock framework for Java”。
在比较 JMockit 的“Mocking Tool Comparision Matrix”的功能时,似乎 JMockit 具有多个不同的功能。

对于 Mockito 可以做什么而 JMockit 无法实现的事情,是否有人有任何具体信息(不是意见),反之亦然?

【问题讨论】:

  • mockito 的可用性可能更好,顺便说一句,我不认为 JMockit 比 Mockito 更成熟...
  • 从票数来看,这个问题的答案显然受到了社区的高度追捧。这意味着导致该问题被关闭的该站点的正交化策略需要进行一些认真的重新思考-因为该站点经常站稳脚跟,能够通过落在其未对齐的正交性上来提供所需的答案。没有意识到在树的图形分析中,查看树的正交性的方法与节点的数量一样多。也许这个网站的正交性,而不是问题的,是错位的。
  • +1 表示不关闭。这些答案很有价值。选择一项技术并不容易,这些问题可以节省大量时间。确实可能没有正确答案,但 StackOverflow 应该可以解决没有答案的问题。
  • 我会支持那些说将其关闭为“不具建设性”是荒谬的。此处提供的答案得到“事实、参考资料和/或专业知识”的支持。技术领域中不引起一些“辩论、投票或扩展讨论”的问题通常几乎不值得问。此外,提供事实和专业知识依赖于不同的经验 - 这些差异将导致辩论和扩展讨论。
  • @Alois - 你能举出 JMockit 看起来不如 Mockito 成熟的具体例子吗?

标签: java unit-testing mocking mockito jmockit


【解决方案1】:

我个人更喜欢EasyMock
在漂亮、正常和严格的模拟控件之间切换的能力是我最喜欢的功能之一。

【讨论】:

    【解决方案2】:

    为了轻松测试我们的遗留代码库(包含大量静态方法调用等),JMockit 非常宝贵。 [在我的博客上无耻地插入article]

    【讨论】:

    【解决方案3】:

    我只使用 jMockit ,因为它是 Deencapsultation.class 中的反射库。我实际上很喜欢 Mockito 的风格,但我拒绝更改我的代码并弄乱我的 API,以便有限的测试框架可以解决它。而且我喜欢测试我的所有代码,所以不能轻易测试私有方法的框架不是我想要使用的。

    我被this article迷住了

    经过(公认的)学习曲线之后,jMockit 现在是我的主要模拟单元测试框架。

    【讨论】:

    • 也许如果你觉得你需要测试私有方法你太关心你的代码是如何工作的,而不是它做了什么(这是真正的重点,可以通过执行它来确定)公共方法)。另外,我有兴趣阅读那篇文章,但链接已损坏。
    • 4 年后,您还在使用 jMockit 作为您的主要测试框架吗?我是第一次尝试它并遇到了一些问题,但我不知道是我误解了 jMockit 的工作原理,还是它是一个根本不存在的功能。
    • jMockit 不再支持测试私有方法。 Deencapsulation 类在版本 1.47 中被慢慢弃用,然后完全删除。 jmockit.github.io/changes.html
    • @Joseph Erickson 你能检查一下stackoverflow.com/questions/63590630/…
    【解决方案4】:

    2019 年 9 月更新:唯一的 mocking framework supported (by default) by Spring BootMockito。如果你使用 Spring,答案就很明显了。


    我想说的是JMockitPowerMock之间的竞争,然后是Mockito

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

    jMock 也有超过 4 年没有稳定的版本。 jMock 2.6.0 从 RC1 升级到 RC2 需要 2 年,然后再需要 2 年才能真正发布。

    关于代理和 CGLIB 与检测:

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

    最终,技术限制 传统的模拟工具强加 以下设计限制 生产代码:

    1. 可能需要在测试中模拟的每个类都必须实现 一个单独的接口或不是最终的。
    2. 必须获得每个要测试的类的依赖关系 通过可配置的实例创建 方法(工厂或服务 定位器),或暴露于依赖 注射。否则,单元测试不会 能够通过模拟实现 对下属单位的依赖 测试。
    3. 由于只能模拟实例方法,因此要对类进行单元测试 不能调用任何静态方法 它们的依赖关系,也不实例化 他们使用任何构造函数。

    以上内容抄自http://jmockit.org/about.html。此外,它还通过多种方式在自身 (JMockit)、PowerMock 和 Mockito 之间进行比较:

    现在有其他模拟工具 Java里面也克服了 传统方法的局限, 它们之间有 PowerMock、jEasyTest 和 模拟注入。最接近的那个 JMockit 的功能集是 PowerMock,所以我将简要评估一下 它在这里(此外,其他两个是 更有限,似乎不是 不再积极开发)。

    JMockit 与 PowerMock

    • 首先,PowerMock没有提供完整的模拟API, 而是作为扩展 另一种工具,目前可以 EasyMock 或 Mockito。这显然是 现有用户的优势 那些工具。
    • 另一方面,JMockit 提供了全新的 API,尽管 它的主要API(期望)是相似的 EasyMock 和 jMock。虽然这 创造了更长的学习曲线,它 还允许 JMockit 提供一个 更简单、更一致、更容易 使用 API。
    • 与 JMockit 期望 API 相比,PowerMock API 是 更“低级”,迫使用户 找出并指定哪些类 需要为测试做好准备(与 @PrepareForTest({ClassA.class, ...}) 注释)并要求 特定的 API 调用来处理 各种语言结构 生产中可能存在的 代码:静态方法 (mockStatic(ClassA.class)), 构造函数 (抑制(构造函数(ClassXyz.class))), 构造函数调用 (expectNew(AClass.class)), 部分 模拟(createPartialMock(ClassX.class, "methodToMock")) 等。
    • 有了JMockit Expectations,各种方法和构造函数都是 以纯粹的声明方式嘲笑, 通过指定的部分模拟 @Mocked 中的正则表达式 注释或简单地“取消模拟” 没有记录的成员 期望;也就是开发商 简单地声明一些共享的“模拟 字段”用于测试类,或一些 “本地模拟字段”和/或“模拟 参数”用于个别测试 方法(在最后一种情况下 @Mocked 注释通常不会 需要)。
    • JMockit 中提供的一些功能,例如对模拟的支持 等于和 hashCode,被覆盖 方法和其他方法目前还没有 PowerMock 支持。此外,还有 不等同于 JMockit 的能力 捕获实例并模拟 指定基础的实现 类型作为测试执行,没有 测试代码本身有任何 实际执行的知识 类。
    • PowerMock 使用自定义类加载器(通常每个测试类一个) 为了生成修改版本 的嘲笑类。如此大量的使用 的自定义类加载器可能导致 与第三方库冲突, 因此有时需要使用 @PowerMockIgnore("package.to.be.ignored") 测试类的注释。
    • JMockit 使用的机制(通过 “Java 代理”)更简单、更安全, 虽然它确实需要通过 “-javaagent”参数到 JVM 时 在 JDK 1.5 上开发;在 JDK 1.6+ (它总是可以用于 开发,即使部署在 旧版本)没有这样的 要求,因为 JMockit 可以 透明地加载 Java 代理 使用 Attach API 来满足需求。

    另一个最近的模拟工具是 莫基托。虽然没有尝试 克服老年人的局限 工具(jMock,EasyMock),它确实 引入一种新的行为方式 用模拟测试。 JMockit 也 支持这种另类风格, 通过 Verifications API。

    JMockit 与 Mockito

    • Mockito 依赖对其 API 的显式调用来分离代码 记录之间 (when(...)) 和 验证(验证(...))阶段。这 意味着对模拟的任何调用 测试代码中的对象也需要 对模拟 API 的调用。 此外,这通常会导致 重复 when(...) 和 验证(模拟)...调用。
    • 使用 JMockit,不存在类似的调用。当然,我们有新的 NonStrictExpectations() 和新的 Verifications() 构造函数调用,但是 它们每次测试只出现一次 (通常),并且完全 与调用分开 模拟方法和构造函数。
    • Mockito API 在用于 对模拟方法的调用。在里面 记录阶段,我们有这样的电话 何时(mock.mockedMethod(args))...而 在验证阶段这个相同的调用 将被写为 验证(模拟).mockedMethod(参数)。 请注意,在第一种情况下 调用 mockedMethod 直接在模拟对象上,而在 第二种情况是在 verify(mock) 返回的对象。
    • JMockit 没有这样的不一致,因为调用 总是制作模拟方法 直接在模拟实例上 他们自己。 (只有一个例外: 匹配相同的调用 模拟实例,一个 onInstance(mock) 调用被使用,导致代码像 onInstance(mock).mockedMethod(args); 大多数测试不需要使用它, 不过。)
    • 就像其他依赖方法的模拟工具一样 链接/包装,Mockito 也运行 存根时语法不一致 无效的方法。例如,你写 when(mockedList.get(1)).thenThrow(new 运行时异常());对于非空 方法和 doThrow(new RuntimeException()).when(mockedList).clear(); 对于一个无效的。使用 JMockit,它是 总是相同的语法: mockedList.clear();结果=新 运行时异常();。
    • 在使用 Mockito 间谍时出现另一个不一致:“模拟” 允许真正的方法是 在间谍实例上执行。为了 例如,如果 spy 指的是一个空的 列出,然后而不是写 when(spy.get(0)).thenReturn("foo") 你 需要写 doReturn("foo").when(spy).get(0).和 JMockit,动态模拟功能 提供类似的功能 间谍,但没有这个问题,因为 真正的方法只在 重播阶段。
    • 在 EasyMock 和 jMock(Java 的第一个模拟 API)中,重点是 完全基于预期的记录 模拟方法的调用,对于 (默认情况下)不模拟的对象 允许意外调用。那些 API 还提供记录 允许对模拟对象的调用 确实允许意外调用, 但这被视为二等 特征。此外,有了这些 工具没有办法明确 在 被测代码被执行。所有这样的 隐式执行验证 并自动进行。
    • 在 Mockito(以及 Unitils Mock)中,相反的观点是 采取。对模拟对象的所有调用 在测试期间可能发生的情况, 无论是否记录,都允许, 没想到。验证是 在代码之后显式执行 在测试中被行使,从不 自动。
    • 这两种方法都过于极端,因此不是最优的。 JMockit 期望和验证 是唯一允许 开发人员可以无缝选择 严格的最佳组合(预期 默认情况下)和非严格(允许 默认)为每个模拟调用 测试。
    • 更清楚地说,Mockito API 有以下缺点。如果你 需要验证对 a 的调用 非空模拟方法发生在 测试,但测试需要一个 从该方法返回值是 不同于默认的 返回类型,然后是 Mockito 测试 将有重复的代码:a when(mock.someMethod()).thenReturn(xyz) 在记录阶段调用,以及 verify(mock).someMethod() 在 验证阶段。使用 JMockit,一个严格的 期待总能被记录, 不必明确 已验证。或者,调用 计数约束(次 = 1)可以是 指定用于任何记录的非严格 期望(与 Mockito 这样的 约束只能在一个 验证(模拟,约束)调用)。
    • Mockito 的验证语法很差 验证(即,检查 所有对模拟对象的调用都是 明确验证)。在第一 情况下,需要一个额外的对象 创建,并调用验证 它: InOrder inOrder = inOrder(mock1, 模拟2,...)。在第二种情况下,调用 像 verifyNoMoreInteractions(mock) 或 verifyZeroInteractions(mock1, mock2) 需要制作。
    • 使用 JMockit,您只需编写 new VerificationsInOrder() 或 new FullVerifications() 而不是 new 验证()(或新 FullVerificationsInOrder() 结合 两个要求)。无需指定 涉及哪些模拟对象。不 额外的模拟 API 调用。而作为一个 奖金,通过调用 unverifiedInvocations() 内 有序的验证块,你可以 执行与订单相关的验证 这在 Mockito 中根本不可能。

    最后,JMockit 测试工具包 范围更广并且更有野心 目标 比其他模拟工具包,在 为了提供一个完整的和 复杂的开发人员测试 解决方案。一个很好的模拟 API,甚至 没有人为的限制,不是 足以生产性地创造 测试。与 IDE 无关,易于使用, 和集成良好的代码覆盖率工具 也是必不可少的,这就是 JMockit Coverage 旨在提供。 开发人员测试的另一部分 将变得更有用的工具集 随着测试套件规模的扩大, 增量重新运行测试的能力 在对生产进行局部更改后 代码;这也包含在 覆盖工具。

    (当然,来源可能有偏见,但好吧......)

    我会说使用 JMockit。当您无法控制要测试的类(或由于兼容性原因等原因无法破坏它)时,它是最容易使用、灵活的,并且适用于几乎所有情况,甚至是困难的情况和场景。

    我对 JMockit 的体验非常积极。

    【讨论】:

    • 我从未使用过 jmockit,但我想在讨论中添加另一个论点:看看所有讨论过的框架的谷歌趋势比较。截至 2012 年 6 月 6 日,与 Mockito 和 EasyMock 相比,JMockit 甚至没有出现在谷歌趋势图上。在选择框架时,用户数量也很重要。
    • 这很奇怪。 Mockito 和 JMockIt 在谷歌上分别给了我 409' 和 83' 的点击率。当然,JMockIt 至少应该出现。
    • 您的回答很有帮助。我计划简单地使用 Mockito,但现在我将首先测试 JMockit。不尝试听起来不错。 @machinery:是的,看趋势很重要,但是选择它作为主要标准会限制你进入主流并阻碍你创新。
    • 我知道这是一个旧线程,但在阅读了这篇评论后,我想我也应该试一试。不得不说,从表面上看,JMockit 是很有前途的。然而,迄今为止,我发现社区对它的支持非常缺乏。我对 Mock API 的理解存在很大问题,在发布我的问题后,我在 2 天内没有任何回应。
    • 答案是8岁,答案中的很多东西都不再正确。有一点是,JMockit 从 1.42 开始就需要 -javaagent 标志,因为自 Java 9 以来您无法再进行自附加,并且找到合适的解决方法显然不在开发人员的范围内。另一点是,JMockit 不再允许模拟私有方法和构造函数,而 PowerMock 则支持 afaik。
    【解决方案5】:

    我曾使用过 Mockito 和 JMockit,我使用它们的经验是:

    • 模拟:

      • 隐式模拟(-> 更好的可用性,但存在无法检测到模拟上不允许的方法调用的危险)
      • 显式验证
    • EasyMock:

      • 显式模拟
      • 隐式验证
    • JMockit:

      • 两者都支持
    • 此外,JMockit 的其他好处:

      • 如果您要模拟静态方法/构造函数等(例如在没有 UT 的情况下扩展非常旧的遗留代码库),您将有两种选择:1) 带有 Powermock 扩展的 Mockito/EasyMock 或 2) Jmockit
      • 内置覆盖率报告

    我个人更喜欢 JMockit,我认为它功能更丰富、更灵活,但需要更陡峭的学习曲线。通常有多种方法可以实现相同的模拟效果,并且在设计模拟时需要更加小心。

    【讨论】:

    猜你喜欢
    • 2013-10-23
    • 2019-07-12
    • 2014-09-14
    • 2011-03-08
    • 2021-05-05
    • 1970-01-01
    • 1970-01-01
    • 2017-02-17
    • 1970-01-01
    相关资源
    最近更新 更多