2013-05-06 31 views
7

我真的已經進入TDD,我已經開始在jUnit中使用mockito來提高我的測試代碼的能力。我真的很愛mockito!在參數上調用靜態方法,而沒有在參數中實例化類

我注意到,我必須改變我對編碼的思考方式,比如儘可能地將合作者傳遞給方法,並儘可能限制構造函數中的工作。

以下情景需要來自SO的專家的一些建議。

說我有一個方法,這將調用某些類的靜態方法。例如。

public void method(){ 
    OtherClass.staticMethod(); 
} 

這通常是不好的,但它在我的情況下是需要的。爲了讓代碼在我的單元測試中更具可測性,我想避免依賴OtherClass並將其作爲參數傳遞。

這不起作用,因爲它會產生編譯時錯誤。

public void method(Class<? extends OtherClass> util){ 
    util.staticMethod(); 
} 
... 
method(OtherClass.class); 

這工作,但我不喜歡實例OtherClass如果我沒有,因爲它是一個純粹的靜態類實用的類似方法:

public void method(OtherClass util){ 
    util.staticMethod(); 
} 
... 
method(new OtherClass()); 

我的問題給你: 有沒有更好的更好的方法來完成這一點,而不使用新的關鍵字?

+2

非常好格式化的問題,爲一個新的用戶,恭喜:) – MarioDS 2013-05-06 06:52:46

+0

我不確定如果你通過一個'OtherClass'子類的實例,你的最後的代碼是否會字。通過實例訪問靜態方法似乎讓我感到困惑,因爲它與該實例無關**,並且它可能無法按照您認爲的方式工作。 – 2013-05-06 06:53:03

+0

順便說一下,在你的情況下使用** Singleton Pattern **而不是靜態方法? – 2013-05-06 06:53:57

回答

0

在您的代碼示例:

public void method(){ 
    OtherClass.staticMethod(); 
} 

我的理解是,應該從靜態方法調用的方法中的一些邏輯上面分開,那就是要測試,而不是靜態的方法是什麼。

如果是這樣的話,您可以編寫OtherClass.staticMethod的模擬實現,它將繞過所有的邏輯或者返回所需的值或實現特定的邏輯。這將避免依賴於OtherClass,並給它測試顯式控制。

0

你可以通過改變你的方法是這樣

public void method(Class<? extends OtherClass> clazz) throws Exception { 
    Method[] mArray = clazz.getMethods(); 
    for(Method m :mArray) { 
     if(!m.isAccessible()) m.setAccessible(true); 
     if((m.getModifiers() & Modifier.STATIC) != 0) { // Here a method which is static is executed. You can change this condition, to suit your needs 
      m.invoke(null); 
     } 
    } 
} 

使用第一種方法,您可以通過調用

method(OtherClass.class); 

沒有通過這個類的一個新對象,調用它

0

您可以使用反射:

// exceptions management omitted 
public void method(Class<? extends OtherClass> clazz, String methodName) { 
    // methodName could also be a constant if it won't change 
    clazz.getMethod(methodName).invoke(null); 
} 

然後,

method(OtherClass.class, "staticMethod"); 
0

這裏是我只是想:

public void testMethod(Class<T> clazz) throws Exception{   
     Method m = clazz.getMethod("staticMethod",null); 
     m.invoke(null,null); 
    } 

我認爲(在你的例子中提到),靜態方法不帶任何參數。

請參考getMethod()inovke()方法的文件。

0

沒有錯一點點靜態代碼在這裏和那裏 - 如果它不訪問全局狀態:

如果靜態代碼是純粹的程序

public void method(){ 
    OtherClass.staticMethod(); 
} 

你可以嘲笑方法(),只要你保持靜態調用作爲你的方法的唯一操作

否則,如果你的靜態方法保護一些全局狀態,你會最好用辛格爾頓+定位

public class Registry { 
    DoSomethingInterface getOtherClass() { 
     return OtherClass.getSingleton(); 
    } 
} 


public void method(Registry reg){ 
    reg.getOtherClass().doSomething(); 
} 

然後你可以繼承註冊表,以提供所有類型的變化對getOtherClass()定位器,這樣你就可以在測試時間實例化的TestRegistry照顧提供一個乾淨的全局狀態和其他東西

如果你仍然需要其他類是靜態的,因爲你不能以任何方式改變它(即庫類),你可以在你的界面把它包裝:

public class Registry { 
    DoSomethingInterface getOtherClass() { 
     return new DoSomethingInterface(){ 
      public void doSomething() { 
       OtherClass.staticMethod(); 
      } 
     }; 
    } 
} 
1

這工作,但我不喜歡實例OtherClass如果我沒有,因爲它是一個純粹類的靜態實用的類似方法:

public void method(OtherClass util){ 
    util.staticMethod(); 
} 
... 
method(new OtherClass()); 

其實,這也不行,因爲它總是會調用從OtherClass方法實現,不論對象的傳遞(即使你通過null)。

我強烈建議不要使用反射只是爲了簡化測試,因爲這會繞過編譯時檢查(錯誤地拼寫的方法名稱不會被編譯器檢測到),並阻止使用IDE的許多功能(代碼完成,javadoc hover,重構支持,調用層次顯示,跳轉到定義,...)

常用的方法是使用多態調度。在Java中,這要求該方法不是靜態的而不是私有的。因此,經驗法則是:如果需要嘲笑,它不應該是靜態的。

如何最好地獲取對象實例取決於您的情況;依賴注入(您的方法),資源定位符模式和單例模式各有其優點和缺點。