簡體   English   中英

我該如何模擬通過Powermock和Mockito通過私有構造函數初始化的私有static final字段?

[英]How do I mock a private static final field initialized via a private constructor using Powermock and Mockito?

這是我的源代碼類-

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

到目前為止,這是我嘗試進行的嘗試

@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassToTest.class)
public class TestClass {
    private ClassToTest testClass;
    @Before
    public void setUp() {
        // each of the below attempts fails at line 1  because of the call to line 2 (annotated above).
        // Attempt A.  
        testClass = WhiteBox.newInstance(ClassToTest.class);
        //Attempt B.
        testClass = mock(ClassToTest.class);
        WhiteBox.setInternalState(ClassToTest.class, "INSTANCE", testClass);
    }
    @Test
    public void dummy() {
        // irrelevant
    }
}

我試圖有效地模擬出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();
    }

PS:我試圖避免處理AbstractSuperClass的內部結構,並且本來希望只是簡單地模擬掉該調用。 我也ClassToTest接受任何重構ClassToTest來避免這種情況的想法。

我不明白您要達到的目標,但這在這里起作用:

@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測試)

我不認為模擬字段是正確的方法,我什至不相信有可能做到這一點,因為您無法覆蓋字段,只有方法可以被覆蓋,這實際上就是模擬的工作方式。 實際上,模擬只是某種程度上可以替代方法的代理。

接下來應模擬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());
    }
}

真正的問題是您通過使用static創建了堅硬的,幾乎無法測試的代碼。 不僅如此:您還會創建一個錯誤的設計 因為您將生產類緊密地耦合在一起。 一旦就位,以后將很難擺脫該靜態方法。

因此,另一個選擇是:后退一步,而不是嘗試使用PowerMock來“修復”損壞的設計。 您將了解“編寫可測試的”代碼實際上是關於什么的(例如,通過觀看這些視頻 ); 然后使用純接口和依賴項注入來解決您的問題。 您可以使用EasyMock或Mockito測試所有功能,而無需Powermock!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM