【问题标题】:Getting around setter injection using mockito's @InjectMocks使用 mockito 的 @InjectMocks 解决 setter 注入
【发布时间】:2013-07-23 18:21:28
【问题描述】:

我有一个带有两个 Map 字段的抽象类。我想模拟并注入 AbstractClass 子类的一个对象以进行单元测试。另一个我真的不太关心,但它有一个二传手。

public abstract class AbstractClass {
    private Map<String, Object> mapToMock;
    private Map<String, Object> dontMockMe;

    private void setDontMockMe(Map<String, Object> map) {
        dontMockMe = map;
    }
}

当使用@InjectMocks 时,它会自动尝试按顺序注入:构造函数、setter、字段。它通过检查类型来检查它是否可以在每个地方注入,然后命名是否有多种类型的可能性。这对我来说效果不佳,因为我的模拟 mapToMock 实际上是通过它的 setter 注入到 dontMockMe 中的。我无法编辑这个抽象类。有什么办法让我绕过二传手注入?提前谢谢!

【问题讨论】:

  • 只是为了纠正你写的东西——Mockito 首先尝试构造函数注入,然后尝试“setter and field”注入,其中可以通过 setter 或直接将模拟注入到字段中。即使你没有这个 setter,你仍然会遇到问题,因为 Mockito 会将你的 mock 注入到这两个字段中。

标签: java unit-testing junit mockito


【解决方案1】:

这是一个极端情况,自动注入无法按照 Mockito 注入的当前设计方式工作。当存在多个具有相同类型的字段时,Mockito 也存在一些缺点。


所以要理解为什么这不起作用,让我们深入了解一下 Mockito 执行注入的方式:

  1. 它将尝试通过构造函数注入来注入依赖项,如果成功则不会尝试以下步骤来保护新创建的实例免受最终副作用的影响。

  2. 然后,如果构造函数注入没有发生(没有 arg 构造函数,或者对象已经实例化),那么 Mockito 将在 mocks 和 setter 之间寻找匹配。但它必须做出一些选择才能让它自动发生。

    1. 如果只有 A 类型的 mock 并且只有一个 A 类型的 setter,则将发生 setter 注入。

    2. 如果有多个模拟或A 类型的设置器,它将尝试使用模拟的类型和名称(通常是@Mock 字段名称)来查找匹配项。如果找到匹配项,则会发生注入。

  3. 如果还有一些 mock 需要注入,可能会发生字段注入,使用与 setter 相同的算法:

    1. 如果只有A 类型的mock,并且只有一个A 类型的字段,则将发生字段注入。

    2. 如果有多个模拟或A 类型的字段,它将尝试使用模拟的类型和名称(通常是@Mock 字段名称)来查找匹配项。如果找到匹配项,则会发生注入。


目前您的代码停留在 2.1 阶段,因为可能只有一个模拟可用。

话虽如此,目前的 Mockito 实现并没有真正优雅的解决方案,有必要自己编写注入代码。这实际上是 Mockito 注入的需要点,如果注入太复杂或奇怪,那么你将不得不把它写出来;编写这个样板代码实际上是质疑当前设计的最佳工具。

Mockito 注入确实是为简单、直接的设计而设计的。

在我看来,我发现错了:

  1. 模拟Map,这是一种您不拥有的类型,这可能会导致很多问题。
  2. 仅在测试对象中模拟单个地图,这意味着您的测试对测试对象的内部工作了解太多。

如果您重构代码并让合作者出现,这将有利于设计。有了明确的依赖关系/合作者,它肯定也会使注入更加清晰。此外,测试应侧重于断言与协作者的交互,而不是数据如何执行,数据应仅作为给定输入的结果进行测试。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-01
    • 2016-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-18
    • 1970-01-01
    • 2021-10-13
    相关资源
    最近更新 更多