我有一个带有两个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注入目前设计的那样工作。当有多个字段具有相同的类型时,Mockito也会遇到一些缺点。
因此,为了理解为什么这不起作用,让我们深入了解Mockito执行注入的方式:
-
它将尝试通过构造函数注入来注入依赖项,如果成功,它将不会尝试以下步骤来保护新创建的实例免受最终的副作用。
-
然后,如果构造函数注入没有发生(没有arg构造函数,或者对象已经实例化),那么Mockito将查找mock和setter之间的匹配。但它必须做出一些选择才能自动发生。
-
如果只有
A
类型的mock,并且只有一个A
类型的setter,则将发生setter注入。 -
如果有多个类型为
A
的mock或setter,它将尝试使用mock的类型和名称(通常是@Mock
字段名)来查找匹配项。如果找到匹配项,则将进行注入。
-
-
然后,如果还有一些mock需要注入,则可能会使用与setter相同的算法进行字段注入:
-
如果只有
A
类型的mock并且只有一个A
类型的字段,则将发生字段注入。 -
如果有多个mock或类型为
A
的字段,它将尝试使用mock的类型和名称(通常是@Mock
字段名称)来查找匹配项。如果找到匹配项,则将进行注入。
-
目前,您的代码停留在2.1阶段,因为可能只有一个mock可用。
也就是说,对于Mockito的当前实现,没有真正优雅的解决方案,有必要自己编写注入代码。这实际上是Mockito注射的要点,如果注射太复杂或太奇怪,那么你必须把它写出来;编写这些样板代码实际上是质疑当前设计的最佳工具。
Mockito注射液是专为简单、笔直的设计而设计的。
在我看来,我发现错误:
- 模拟
Map
,一个你不拥有的类型,这可能会导致很多问题 - 只模拟测试对象中的单个映射,这意味着您的测试对测试对象的内部工作了解太多
如果你重构代码并让合作者出现,这将有利于设计。有了明确的依赖关系/协作者,它肯定也会使注入更加清晰。此外,测试应侧重于断言与合作者的交互,而不是如何数据实现,数据应仅作为给定输入的结果进行测试。