2

I have an abstract class with two Map fields. One I would like to mock and inject into an object of a subclass of AbstractClass for unit testing. The other I really don't care much about, but it has a setter.

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

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

When using @InjectMocks, it automatically tries to inject in the order: constructor, setter, field. It checks if it can inject in each of these places by checking types, then names if there are multiple type possibilities. This doesn't work well for me, because my mocked mapToMock is actually injected into dontMockMe via its setter. I cannot edit this abstract class. Is there any way for me to get around the setter injection? Thank you in advance!

4

1 回答 1

3

好吧,这是一个极端情况,自动注入不会像 Mockito 注入当前设计的那样工作。当存在多个具有相同类型的字段时,Mockito 也存在一些缺点。


因此,要了解为什么这不起作用,让我们深入了解 Mockito 执行注入的方式:

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

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

    1. 如果只有类型的模拟A并且只有一个具有类型的设置器,A那么将发生设置器注入。

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

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

    1. 如果只有一个类型的模拟A并且只有一个类型的字段,A那么就会发生字段注入。

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


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

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

Mockito 注射真的是为简单、直接的设计而设计的。

在我看来,我发现错误:

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

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

于 2013-07-24T11:27:28.050 回答