【问题标题】:Unable to override static final variable of a final class using PowerMock无法使用 PowerMock 覆盖最终类的静态最终变量
【发布时间】:2018-07-29 22:21:06
【问题描述】:

我正在尝试使用 PowerMock Whitebox setInternalState api 来覆盖最终类的静态最终变量。但这似乎不起作用。请看下面的示例代码:

带有静态最终变量的最终类:

public final class BuildConfig {
    public static final String BUILD_TYPE = "debug";
}

返回上述变量的辅助类:

public class BuildConfigHelperClass {
    public String getBuildType() {
        return BuildConfig.BUILD_TYPE;
    }
}

测试类

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;

import static org.junit.Assert.*;
import static org.powermock.api.mockito.PowerMockito.mockStatic;

@RunWith(PowerMockRunner.class)
@SuppressStaticInitializationFor("BuildConfig")
@PrepareForTest({BuildConfigHelperClassTest.class, BuildConfigHelperClass.class, BuildConfig.class})
public class BuildConfigHelperClassTest {

    private BuildConfigHelperClass subject;

    @Before
    public void setUp() {
        subject = new BuildConfigHelperClass();
    }

    @Test
    public void shouldReturnDebugBuildType() {
        assertEquals("debug", subject.getBuildType());
    }

    @Test
    public void shouldReturnProductionBuildType() {
        mockStatic(BuildConfig.class);
        Whitebox.setInternalState(BuildConfig.class, "BUILD_TYPE", "production");
        assertEquals("production", subject.getBuildType());
    }
}

在上面的测试类中,第二个测试subject.getBuildType() 方法应该返回“production”,因为我通过 Whitebox 覆盖它,但它总是因为返回值(即“debug”)而失败。

任何人都可以指导我了解我所缺少的内容。

【问题讨论】:

    标签: java android unit-testing powermock powermockito


    【解决方案1】:

    编译器正在优化代码,其中:

    public class BuildConfigHelperClass {
        public String getBuildType() {
             return BuildConfig.BUILD_TYPE;
       }
    }
    

    本质上编译为:

    public class BuildConfigHelperClass {
        public String getBuildType() {
             return "debug";
       }
    }
    

    所以单元测试是针对没有参考 BuildConfig 的编译代码运行的。

    不要直接引用BUILD_TYPE,而是尝试添加一个静态getter:

    public final class BuildConfig {
        private static final String BUILD_TYPE = "debug";
    
        public static final String getBuildType() {
            return BUILD_TYPE;
        }
    }
    

    那么静态方法就可以mock了:

    @Test
    public void shouldReturnProductionBuildType() {
        mockStatic(BuildConfig.class);
        // Whitebox.setInternalState(BuildConfig.class, "BUILD_TYPE", "production");
        PowerMockito.when(BuildConfig.getBuildType()).thenReturn("production");
        assertEquals("production", subject.getBuildType());
    }
    

    这个测试在我的本地运行,尽管其他编译器可能仍然能够优化它并破坏测试。

    【讨论】:

    • 感谢您的方法很好。但是如果我们无法控制 BuildConfig 类来修改它(在我的情况下我无法修改它)。那么这种方式就不能用了。
    • 由于BUILD_TYPE 被定义为静态最终值,因此试图操纵它的单元测试的值是有问题的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多