2016-04-23 91 views
1

我試圖測試下面的類,它調用一個單例,通過嘲笑它來初始化一個私有靜態最終變量,遵循this示例。我在做什麼錯用mockito和反射嘲笑這個私有靜態最終變量?

下面是我在做什麼

public class ClassToTest { 

private static final boolean CONF_FLAG = Configuration.getConfig() 
.get(Status.Initialization).getConfFlag(); // throws an NPE 

public methodToTest(TestObject a){ 
... 
} 
} 

,其中狀態是一個枚舉。

測試類:

public class TestClassToTest{ 

TestObject a; 
ClassToTest t; 
    @Before 
public void setUp() throws Exception { 
    setFinalStatic(ClassToTest.class.getDeclaredField("CONF_FLAG"), true);// this fails! 
    a = mock(TestObject.class); 
    t = new ClassToTest(); 
} 
static void setFinalStatic(Field field, Object newValue) throws Exception { 
    field.setAccessible(true);   
    Field modifiersField = Field.class.getDeclaredField("modifiers"); 
    modifiersField.setAccessible(true); 
    modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); 
    field.set(null, newValue); 
} 

}

我不關心的CONF_FLAG價值,但不能似乎嘲笑它。我究竟做錯了什麼?

回答

1

當你的類加載那麼這行被稱爲

private static final boolean CONF_FLAG = Configuration.getConfig().get(Status.Initialization).getConfFlag(); 

因此,要解決我想建議使用PowerMock問題。

使用PowerMock,您可以使用@SuppressStaticInitilizationFor輕鬆跳過unnecessary behavior

此外,您將能夠輕鬆設置內部狀態:

Whitebox.setInternalState(ClassToTest.class, "CONF_FLAG", true) 

當然,它會在情況下工作,如果你可以添加一個新庫。

1

你在TestClassToTest代碼看起來不錯,但訪問ClassToTest.class.getDeclaredField("CONF_FLAG")將初始化靜態最終ClassToTest#CONF_FLAG字段,它表明在NullPointerException結果。

我假設您無法修改ClassToTest中的源代碼。作爲一個修補程序,是否還有其他任何可以在setUp()中使用的方法來初始化Configuration單例,例如使用其公共API方法,以便Configuration.getConfig().get(Status.Initialization).getConfFlag()調用成功?

如果是這樣,您可以採取這種方法爲您的測試準備Configuration對象,而不是使用反射。

+0

+1。要在此添加,只要該呼叫作爲靜態字段初始化的一部分發生,您將幾乎不能控制呼叫的時間,並且實際上沒有機會將其替換爲測試。作爲一個經驗法則,如果一個調用足夠危險,可能拋出一個異常或在測試中保證嘲笑,你不希望它在任何靜態初始化器中。 –

+0

@Jeff Bowman,@ ck1是的,我完全理解關於不將它放置在靜態初始化器中的部分,但這是一個遺留代碼,我被打了一巴掌,我有點不習慣在我的周圍工作。 'getConfig()'是一個靜態方法..有什麼辦法可以模擬/存根整個調用單身?如果是的話,Id非常感謝一些代碼/僞代碼。 – MuleNoob