当使用Mockito 1.9.x时,我一直在使用Whitebox
设置字段值以“注入(inject)”模拟。 Se示例如下:
@Before
public void setUp() {
eventHandler = new ProcessEventHandler();
securityService = new SecurityServiceMock();
registrationService = mock(RegistrationService.class);
Whitebox.setInternalState(eventHandler, "registrationService", registrationService);
Whitebox.setInternalState(eventHandler, "securityService", securityService);
}
我真的很喜欢这种方法,但是现在我尝试升级到
Mockito
2.2.7
,我注意到(或者更确切地说,我的IDE注意到并告诉我很多次)在Mockito中不再存在Whitebox。我发现了一个替代方法,可以替代它,即
org.powermock.reflect.Whitebox
,问题在于我得到了另一个依赖项(Powermock),仅用于使用Whitebox。Powermock
也有一个名为Whitebox
的类,但不幸的是,它看起来好像无法与Mockito 2.2.x
一起使用现在
Whitebox
不再可用,我可以在Mockito中使用任何好的替代方法来手动“注入(inject)”字段吗?解
我在评论中写了@JeffBowman的帖子。简而言之,我选择复制并使用WhiteBox的代码,因为大多数测试用例中都使用了它,并且该类与其他类没有依赖关系。这是解决此问题的最快途径。
注意 @bcody建议的解决方案是更好的选择,如果您使用的是spring,则它不会增加任何代码供您维护。我知道这些信息了:(
最佳答案
请注意,Whitebox
始终位于org.mockito.internal
包中。除了增加主版本号外,internal
的名称还表明该软件包可能会受到重大更改。
如果您确实希望在测试中设置否则无法访问的字段,可以按照与setInternalState
相同的方式进行操作,即识别层次结构中的字段,在其上调用setAccessible
,然后进行设置它。 The full code is here on grepcode.您还可以检查一些other ways to set inaccessible state in tests。
public static void setInternalState(Object target, String field, Object value) {
Class<?> c = target.getClass();
try {
Field f = getFieldFromHierarchy(c, field); // Checks superclasses.
f.setAccessible(true);
f.set(target, value);
} catch (Exception e) {
throw new RuntimeException(
"Unable to set internal state on a private field. [...]", e);
}
}
但是,在这种情况下,,我的一般建议是停止使用这些工具:Java的四个封装级别(公共(public),保护,程序包,私有(private))不一定足以表示您要表达的保护程度,并且在尝试进行反射(reflection)时,添加记录良好的初始化方法或构造函数重写来覆盖依赖关系通常会容易得多。如果将测试与所测试的类放在同一Java包中,则通常甚至可以将字段或方法/构造器包设为私有(private),这也是设置并行源文件夹
src
和tests
(等)的一个很好的理由。代表同一Java包的两半。尽管有些人将这种额外的方法或构造函数视为“API污染”,但我认为它是按照类(class)最重要的使用者之一的要求(即自己的测试)进行编码。如果您需要原始的外部接口(interface),则可以轻松地单独定义一个接口(interface),以便隐藏所需的任何细节。但是,您可能会发现自己喜欢将任何真实或模拟实现直接注入(inject)到现在更加灵活的组件中的能力,此时,您可能希望研究依赖项注入(inject)模式或框架。