Java 如何使用Powermock和Mockito模拟通过私有构造函数初始化的私有静态final字段?

Java 如何使用Powermock和Mockito模拟通过私有构造函数初始化的私有静态final字段?,java,unit-testing,mockito,powermock,white-box,Java,Unit Testing,Mockito,Powermock,White Box,这是我的源代码类- public class ClassToTest extends AbstractSuperClass<Integer> { private static final ClassToTest INSTANCE = new ClassToTest(); // (line 1) need to mock this variable static ClassToTest get() { return INSTANCE; }

这是我的源代码类-

public class ClassToTest extends AbstractSuperClass<Integer> {
    private static final ClassToTest INSTANCE = new ClassToTest(); // (line 1) need to mock this variable

    static ClassToTest get() {
        return INSTANCE;
    }
    private ClassToTest() {
        super(Integer.class);// (line 2)
    }
}
我试图有效地模拟
ClassToTest.INSTANCE
及其私有构造函数的调用。我怎么能这么做

编辑:从
AbstractSuperClass
调用代码段/构造函数

public abstract class AbstractSuperClass<V extends Serializable> {
    private final CacheClient<V> cache;
    private final int seconds;

    public AbstractSuperClass(Class<V> valueType) {
        cache = new ClientFactory(Config.getAppConfig(), StatisticSet.getGlobalStatistics()).newClient(getCacheType(), valueType);
        seconds = Config.getAppConfig().get(getCacheType().getSectionEnum()).getSeconds();
    }
公共抽象类AbstractSuperClass{
专用最终缓存客户端缓存;
私人最后整数秒;
公共抽象超类(类valueType){
cache=newclientfactory(Config.getAppConfig(),StatisticSet.getGlobalStatistics()).newClient(getCacheType(),valueType);
seconds=Config.getAppConfig().get(getCacheType().getSectionEnum()).getSeconds();
}

附言:我正试图避开处理
抽象超类的内部问题,原本希望简单地模拟调用。我也愿意接受任何重构
类totest
以避免这种情况的想法。

我不相信模拟字段是正确的方法,我甚至不相信有可能按的方式操作你不能覆盖一个字段只能覆盖方法,这实际上就是mock的工作方式。实际上,mock只是我们覆盖方法的某种代理

您应该将
ClassToTest.get()模拟为下一个:

@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassToTest.class)
public class TestClass {
    private ClassToTest testClass;
    @Before
    public void setUp() {
        testClass = PowerMockito.mock(ClassToTest.class);
        PowerMockito.mockStatic(ClassToTest.class);
        Mockito.when(ClassToTest.get()).thenReturn(testClass);
    }

    @Test
    public void dummy() {
        // Here I get the instance of ClassToTest that I mocked in the setUp method
        System.out.println(ClassToTest.get());
    }
}

你的真正的问题是,你使用静态创建了难以测试的几乎不可测试的代码。不仅如此:你还创建了一个糟糕的设计。因为你的生产类彼此紧密耦合。一旦到位,以后要摆脱这种静态方法将非常困难开


因此,另一种选择是:不要试图使用PowerMock“修复”一个损坏的设计,而是退后一步,学习“编写可测试”代码的真正意义(例如通过观看这些);然后您使用纯接口和依赖注入来解决您的问题。您可以使用EasyMock或Mockito来测试所有这些,而不需要Powermock!

我不明白您想要实现什么,但这在这里起作用:

@PrepareForTest(ClassToTest.class) // required
@RunWith(PowerMockRunner.class)    // required
public class ClassToTestTest {

    private ClassToTest testClass;

    @Before
    public void setUp() throws Exception {
        this.testClass = Mockito.mock(ClassToTest.class);
        final Field instance = ClassToTest.class.getDeclaredField("INSTANCE");
        instance.setAccessible(true);
        instance.set(null, this.testClass);
    }

    @Test
    public void testGet() throws Exception {
        assertSame(this.testClass, ClassToTest.get());
        System.out.println(this.testClass);
    }
}
输出:

Mock for ClassToTest, hashCode: 1083021083

(使用powermock api mockito 1.6.2版进行测试)

如果您将
testClass.doSomething();verify(testClass.doSomething();
添加到
dummy
方法中,那么您的模拟
ClassToTest.INSTANCE
接缝解决方案将起作用,因此我看不出实际问题是什么(我使用了尝试B)。你能添加一些关于问题的更多信息吗?@GergelyToth-我猜这可能与私有构造函数调用
AbstractSuperClass
有关,我已经编辑了这个问题并添加了类的更多细节。我很好奇是否有任何使用Mockito/PowerMock解决这个问题的方法。在我的案例I希望测试另一个依赖项为
ClassToTest
的类,因此我基本上将
ClassToTest
提取到一个接口,并为测试目的提供了一个模拟实现,类似于在
PowerMockito.mock(ClassToTest.class)中解释的失败
再次分别由第1行和第2行引起,这意味着调用没有被模拟:(.我复制/粘贴了没有AbstractSuperClass的代码,因为您没有提供它,它可以工作请提供AbstractSuperClassthen@NicolasFilotto,我认为这可能是我们看到不同结果的不同(?)在我的例子中,
AbstractSuperClass
实际上加载了一系列配置,
super()
可能是导致失败的原因。如果您不按照MCVE规则提供缺少的类,则很难提供帮助。Powermock是一个残酷的情妇-它将在短期内帮助您,但在长期内伤害您。如前所述,它安抚了糟糕的设计,同时消耗了您的
@RunWith
,并可能导致棘手的兼容性问题和其他库一样,因为它的作用。通常,生活中的一切,以及it生活中的一切都是关于平衡的。如果你处理的是第三方/遗留代码;你可以或不想更改;那么Powermock可能仍然有用。但非常简单的规则是:如果你正在创建新代码,那么你就不需要Powermock。故事结束。
Mock for ClassToTest, hashCode: 1083021083