PowerMock testing - set static field of class

2019-01-17 13:54发布

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.

5条回答
Rolldiameter
2楼-- · 2019-01-17 14:34

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.

查看更多
Summer. ? 凉城
3楼-- · 2019-01-17 14:37

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);
            }       }
查看更多
聊天终结者
4楼-- · 2019-01-17 14:54

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".

查看更多
爱情/是我丢掉的垃圾
5楼-- · 2019-01-17 14:55

You simply do:

Whitebox.setInternalState(Foo.class, b);

where b is the instance of B that you want to set.

查看更多
甜甜的少女心
6楼-- · 2019-01-17 14:59
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 );
查看更多
登录 后发表回答