Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I set a primitive private static final field in a class with private constructor using PowerMockito?

I'm trying to set a private static final field in a class with private constructor for a JUnit test. When I boil the code down to its basics, I get the following:

public class Foo {
    private static final boolean FLAG = false;
    private Foo() { /* don't call me */  }
    public static boolean get() { return FLAG; }
}

My tests looks like this:

@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());
    }
}

And here is an excerpt from my POM file:

<junit.version>4.11</junit.version>
<powermock.version>1.5.4</powermock.version>
<mockito.version>1.9.5</mockito.version>

When I put a breakpoint on return FLAG;, I can clearly see that FLAG was set to true in IntelliJ's debugger. Yet the test fails with an AssertionError.

Any ideas what to do to make this work?

Update: using reflection doesn't seem to work, either:

@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);
}

The setField() method is one I have available through an internal library. Unfortunately, it produces the same result: AssertionError

Update 2: Getting completely rid of PowerMock doesn't help much, either, apparently:

@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);
}

For this, I even removed the PowerMock annotations from the class level...

I've also posted this question to the PowerMock mailing list now.

like image 397
Christian Avatar asked Oct 22 '15 12:10

Christian


1 Answers

I had similar thing to test, but the only difference was that my static final variable was an Object rather than primitive type. And indeed changing boolean to Boolean makes it work.

public class Foo {
    private static final Boolean FLAG = false;
    private Foo() { /* don't call me */  }
    public static boolean get() { return FLAG; }
}

Also I would recommend using @PrepareForTest(SomeClass.class) where SomeClass has static final field rather than @PrepareEverythingForTest because if it's big project it may take some time prepare everything.

like image 189
Templar Avatar answered Oct 23 '22 12:10

Templar