我尝试使用private static final
构造函数在类中设置private
字段以进行JUnit测试。当我将代码简化为基础时,我得到以下内容:
public class Foo {
private static final boolean FLAG = false;
private Foo() { /* don't call me */ }
public static boolean get() { return FLAG; }
}
我的测试看起来像这样:
@RunWith(PowerMockRunner.class)
@PrepareEverythingForTest // Whitebox fails without this line
public class FooTest {
@Test
public void testGet() {
Whitebox.setInternalState(Foo.class, "FLAG", true);
assertTrue(Foo.get());
}
}
以下是我的POM文件的摘录:
<junit.version>4.11</junit.version>
<powermock.version>1.5.4</powermock.version>
<mockito.version>1.9.5</mockito.version>
当我在return FLAG;
上放置断点时,我可以清楚地看到IntelliJ的调试器中FLAG
设置为true
。然而,测试失败了AssertionError
。
任何想法如何使这项工作?
使用反射的更新似乎无效:
@Test
public void testGet_usingReflection() throws Exception {
setField(Whitebox.invokeConstructor(Foo.class), "FLAG", true);
assertTrue(Foo.get());
}
public static void setField(Object targetObject, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
Class clazz = targetObject.getClass();
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
Field modifiers = Field.class.getDeclaredField("modifiers");
modifiers.setAccessible(true);
modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(targetObject, value);
}
setField()
方法是我通过内部库提供的方法。不幸的是,它会产生相同的结果:AssertionError
更新2:显然,完全摆脱PowerMock并没有多大帮助:
@Test
public void testGet_usingReflectionWithoutPowerMock() throws Exception {
setField(Foo.class.getDeclaredField("FLAG"), true);
assertTrue(Foo.get());
}
public static void setField(Field field, Object value) throws NoSuchFieldException, IllegalAccessException {
field.setAccessible(true);
Field modifiers = Field.class.getDeclaredField("modifiers");
modifiers.setAccessible(true);
modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, value);
}
为此,我甚至从班级中删除了PowerMock注释......
我现在也已将此问题发布到PowerMock mailing list。
答案 0 :(得分:2)
我有类似的测试,但唯一的区别是我的静态最终变量是Object
而不是原始类型。确实将boolean
更改为Boolean
会使其有效。
public class Foo {
private static final Boolean FLAG = false;
private Foo() { /* don't call me */ }
public static boolean get() { return FLAG; }
}
另外,我建议使用@PrepareForTest(SomeClass.class)
其中SomeClass
有静态最终字段而不是@PrepareEverythingForTest
,因为如果它是一个大项目,可能需要一些时间准备一切。
答案 1 :(得分:0)
WhiteBox.setInternalState不适用于带有final字段的类。
您可以使用Reflection来解决此问题:
static void setFinalStatic(Field field, Object newValue) throws Exception {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}