PowerMock testing - set static field of class
JunitStaticMockingPowermockJunit Problem Overview
I'm having difficulty finding a way to set a static field of a class. It's basically like this:
public class Foo{
// ...
private static B b = null;
}
where B is another class.
Is there any way to do this in PowerMock other than with setInternalStateFromContext()
? Using the context class method seems a bit of overkill for setting one field.
Thanks.
Junit Solutions
Solution 1 - Junit
Whitebox.setInternalState(Foo.class, b);
Works as long as you set a non-null value, and if theres only one field with the class of B
. If you can't rely on that luxury, you have to provide the field-name and cast the null
to the type you want to set. In that case you would need to write something like this:
Whitebox.setInternalState( Foo.class, "b", (B)null );
Solution 2 - Junit
Try this:
@RunWith(PowerMockRunner.class)
@PrepareForTest({Foo.class})
public class FooTest {
@Test
public void shouldMockPrivateStaticField() throws IllegalAccessException {
// given
Foo foo = new Foo();
Field field = PowerMockito.field(Foo.class, "b");
field.set(Foo.class, mock(B.class));
Don't work for primitives and primitives wrappers.
Solution 3 - Junit
You simply do:
Whitebox.setInternalState(Foo.class, b);
where b is the instance of B that you want to set.
Solution 4 - Junit
here I am going to set value for "android.os.Build.VERSION.RELEASE", where VERSION is the class name and RELEASE is the final static string value.
> If the underlying field is final, the method throws an > IllegalAccessException unless setAccessible(true) has succeeded for > this field and this field is non-static, NoSuchFieldException needs to be added when you use field.set() method
@RunWith(PowerMockRunner.class)
@PrepareForTest({Build.VERSION.class})
public class RuntimePermissionUtilsTest {
@Test
public void hasStoragePermissions() throws IllegalAccessException, NoSuchFieldException {
Field field = Build.VERSION.class.getField("RELEASE");
field.setAccessible(true);
field.set(null,"Marshmallow");
}
}
now the value of String RELEASE will return "Marshmallow".
Solution 5 - Junit
Whitebox.setInternalState(Foo.class, "FIELD_NAME", "value");
Solution 6 - Junit
You can use getAllStaticFields
and try to set them
Example:
YourFieldClass newValue;
final Set<Field> fields = Whitebox.getAllStaticFields(YourClass.class);
for (final Field field : fields) {
if (YourFieldClass.class.equals(field.getType())) { // or check by field name
field.setAccessible(true);
field.set(YourClass.class, newValue);
} }