2012-03-14 84 views
27

我使用JUnit4和Cobertura僅使用靜態方法來測試幫助程序類。測試方法很容易,已經完成。JUnit:僅使用靜態方法測試幫助程序類

但是,cobertura顯示該類未完全覆蓋測試,因爲它未在任何地方實例化。

我不想創建這個類的實例(它是一個輔助類),所以第一個解決方案是隱藏構造函數(這通常是輔助類的好方法)。

然後cobertura抱怨空的私人構造函數未被測試覆蓋。

是否有任何解決方案來實現100%的代碼覆蓋這種情況?

代碼覆蓋率是來自頂級管理(在這種情況下)的要求,所以對於我爲這個特定類獲得100%是相當有幫助的。

回答

27

有幾種解決方案:

  1. 您可以添加一個公共構造函數,並從測試調用它。雖然它沒有意義,但它也不會傷害(很多)。

  2. 創建一個虛擬靜態實例(您可以在這裏調用私有構造函數)。醜,但你可以給這個領域一個名字來傳達你的意圖(JUST_TO_SILENCE_COBERTURA是個好名字)。

  3. 你可以讓你的測試擴展輔助類。這將內在地調用默認的構造函數,但你的幫助類不能再是final

我建議最後一種方法,特別是因爲班級不能再final。如果您的代碼的使用者想要添加另一個幫助器方法,他們現在可以擴展現有的類並接收一個句柄以獲取所有幫助器方法。這就形成了其通信的意圖的輔助方法的耦合(這屬於一起) - 這是不可能的,如果輔助類是final

如果要防止用戶意外初始化助手類,使它abstract而不是使用一個隱藏的構造函數。

+1

第三種方法在我看來是最好的,因爲它根本不影響代碼(只有測試)。我會採取這種方式。謝謝你的幫助。 – 2012-03-14 11:43:16

2

除非你顯式調用私有構造函數(這將是糟糕的代碼),你將無法覆蓋這些行。

7

在所有情況下獲得100%的覆蓋率都很好,但在某些情況下這是不可能的。當然,如果你有一個從未實例化過的類,Cobertura會將其作爲一個不完整的測試覆蓋率,因爲這些代碼行實際上在類中,但它們沒有經過測試。事實上,你永遠不會調用一個私有構造函數(我假設你已經隱藏了構造函數,因爲它是私人的),所以我不打擾。測試應該是關於如何得到你所期望的,雖然我同意100%覆蓋率是好的,但在某些情況下(如這樣),這是沒有用的。

看看100% Code Coverage以及。

+2

有時代碼覆蓋需要從頂層管理(在這種情況下),所以對於我來說,爲這個特定類獲得100%是相當有幫助的。是的 - 我知道這種方法的荒謬。但是 - 感謝您的文章鏈接。 – 2012-03-14 11:41:44

27

如果您絕對需要實現100%的代碼覆蓋率 - 其優點可以在別處討論:) - 您可以在測試中使用反射來實現它。作爲習慣,當我實現一個靜態實用類時,我添加了一個私有構造函數來確保無法創建該類的實例。例如:

/** 
* Constructs a new MyUtilities. 
* @throws InstantiationException 
*/ 
private MyUtilities() throws InstantiationException 
{ 
    throw new InstantiationException("Instances of this type are forbidden."); 
} 

然後測試可能是這個樣子:

@Test 
public void Test_Constructor_Throws_Exception() throws IllegalAccessException, InstantiationException { 
    final Class<?> cls = MyUtilties.class; 
    final Constructor<?> c = cls.getDeclaredConstructors()[0]; 
    c.setAccessible(true); 

    Throwable targetException = null; 
    try { 
     c.newInstance((Object[])null); 
    } catch (InvocationTargetException ite) { 
     targetException = ite.getTargetException(); 
    } 

    assertNotNull(targetException); 
    assertEquals(targetException.getClass(), InstantiationException.class); 
} 

基本上,你在做什麼在這裏越來越名字的類,這個類的類型尋找構造,設置它公開(調用setAccessible),調用沒有參數的構造函數,然後確保拋出的目標異常是InstantiationException

無論如何,正如你所說的,這裏100%的代碼覆蓋率要求是一種痛苦,但它聽起來好像不在你的手中,所以你對此無能爲力。實際上,我在自己的代碼中使用了與上面類似的方法,並且我確實發現它有益處,但不是從測試角度來看。相反,它只是幫助我學習更多關於思​​考的知識,而不是我之前所知道的:)

+1

+1 Nice hack :-) – 2012-03-14 16:33:54

+0

+1,聰明的解決方案! – JW8 2012-09-25 21:13:38

+0

爲什麼在catch塊中存在'return'?測試將始終返回true。 ;) – 2015-05-14 06:01:58