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

Chr*_*ian 6 java reflection junit intellij-idea powermockito

我正在尝试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; }
}
Run Code Online (Sandbox Code Playgroud)

我的测试如下所示:

@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());
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的 POM 文件的摘录:

<junit.version>4.11</junit.version>
<powermock.version>1.5.4</powermock.version>
<mockito.version>1.9.5</mockito.version>
Run Code Online (Sandbox Code Playgroud)

当我在 上设置断点时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);
}
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

为此,我什至从类级别删除了 PowerMock 注释......

我现在也将此问题发布到PowerMock 邮件列表

Max*_*ime 0

WhiteBox.setInternalState 不适用于具有最终字段的类。

您可以使用反射来解决此问题:

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);  
}  
Run Code Online (Sandbox Code Playgroud)

来源: https: //code.google.com/p/powermock/issues/detail? id=324

  • 好吧,根据 PowerMock 组中的[这篇文章](https://groups.google.com/d/msg/powermock/SfQygHwGeGY/SKsigfkiFS8J),“Whitebox”应该能够设置“final”字段,前提是类已准备好进行测试。我也尝试过反射,结果几乎相同(即不工作)。我相应地更新了帖子。 (3认同)