java – 如何使用PowerMockito在具有私有构造函数的类中设置原始私有静态final字段?

我正在尝试使用私有构造函数在类中设置私有静态final字段以进行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>

当我在返回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.

最佳答案 我有类似的东西要测试,但唯一的区别是我的静态最终变量是一个Object而不是原始类型.实际上,将布尔值更改为布尔值会使其工作.

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,因为如果它是大项目,可能需要一些时间准备一切.

点赞