我在Mockito 2.2中使用什么代替Whitebox来设置字段?

当使用Mockito 1.9.x时,我一直在使用Whitebox来设置字段值以“注入”模拟。 以下示例:

 @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一起使用

Mockito有什么好的选择,我可以用来手动“注入”字段,现在Whitebox已不再可用吗?


我在回复@JeffBowman的post时写了一篇评论。 简而言之,我选择复制WhiteBox的代码,并使用它,因为它在大多数测试用例中使用,并且该类与其他类没有依赖关系。 这是解决这个问题的最快途径。

注意 @bcody建议的解决方案是一个更好的选择,如果你使用spring,它不会为你维护额外的代码。 我得到的信息很晚了:(

请注意, Whitebox始终位于org.mockito.internal包中。 除了主要版本号的增加之外, internal名称是赠品,包装可能会受到重大变化。

如果你想在测试中设置其他不可访问的字段,你可以像setInternalState那样做,这只是为了识别层次结构中的字段,在其上调用setAccessible ,然后设置它。 完整的代码在grepcode上。 您还可以检查许多其他方法来设置测试中的不可访问状态 。

 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的四个封装级别(公共,受保护,封装,私有)不一定非常精细,足以表达您试图表达的保护程度,并且添加一个记录良好的初始化方法或构造函数覆盖来覆盖依赖关系通常要容易得多,因为你正试图反思。 如果你把你的测试放在与它测试的类相同的Java包中,你通常甚至可以使字段或方法/构造函数包为private,这也是设置并行源文件夹srctests (等)的一个很好的理由。表示同一Java包的两半。

虽然有些人将这种额外的方法或构造函数视为“API污染”,但我认为它可以编码满足您的一个类最重要的消费者的需求 – 它自己的测试 。 如果您需要一个原始的外部界面,您可以轻松地单独定义一个,以便您可以隐藏任何您想要的细节。 但是,您可能会发现自己喜欢将任何实际或模拟实现直接注入到现在更灵活的组件中,此时您可能希望查看dependency injection模式或框架。

如果您使用的是Spring(特别是spring-test库),您只需使用ReflectionTestUtils.setField而不是Whitebox.setInternalState

FieldUtils ,最新和最便携的方式是使用Apache Commons的FieldUtils而不重新发明轮子。 https://commons.apache.org/proper/commons-io/javadocs/api-2.5/org/apache/commons/io/FileUtils.html

那么你的问题的答案就是

 public static void setStaticFieldValue( @NonNull final Class clz, @NonNull final String fieldName, @NonNull final Object value) throws Exception { final Field f = FieldUtils.getField(clz, fieldName, true); FieldUtils.removeFinalModifier(f); f.set(null, value); }