2015-04-28 109 views
1

JUnit測試我讀了這個問題:How do I test a class that has private methods, fields or inner classes?,似乎我可能有一個代碼味道,但我的代碼是非常簡單的實際重構。我創建的設計出了什麼問題。 我創建了一個委託類處理一些行動有三個方法execute(Action);PopulateActionHandlers()executeActionhandlers(); 我的類象下面這樣:私人方法

public class DelegateHandler{ 
    Map<Integer,ActionHandlers> handlerMaps; 

    public execute(Action action){ 
     populateActionHandlers(action); 
     executeActionHandlers(); 

    }//end of execute 

    //This method can create and populate more than one handlers in handlerMap 
    private populateActionHandlers(action){ 
     handlerMap = new LinkedHashMap<ActionHandlers>(); 
     if (action.isMultimode()){ 
      handlerMap.add(1,new handler(action.getabc())); 
      handlerMap.add(2,new handler(action.getabc()-1)); 
     }else{ 
      handlerMap.add(1,new handler(action)); 
     } 

    }//end of populateActionHandlers 

    //This method can execute more than one handlers in handlerMap 
    private executeActionHandlers(){ 
     for(ActionHandler actionHandler : handlerMap.values){ 
      actionHandler.executeAction(); 
     } 

    }//end of executeActionHandlers 
} 

現在我想測試populateActionHandlers()方法使用JUnit,我做私人的有無需在課堂以外暴露。如果我測試​​方法,然後將測試這兩個populateActionHandlers()executeActionHandlers()方法,這是在同一時間測試兩個單位,我想單獨測試。設計(我認爲)對我來說似乎是好的,並且不允許任何問題,但是我會改變對該方法的訪問權限(並且僅僅爲了測試而沒有證明在我看來是正確的?)或者使用反思(這是一個好主意,它以某種方式感覺不對,人們通常使用反射進行junit測試?)。所以唯一不能排除的就是代碼味道。但可能是我的代碼竇是不是真的幫助我所以我想了解,如果我可以改善這個代碼。

+4

我不認爲測試公共方法是測試兩件事。只有一項公共行動。該課程只暴露一個公共「事物」。你會測試那件事。現在,您可能有多個測試在多種不同的前提條件下調用這一件事,以便測試其中的各個代碼路徑。但是,測試一個班級的公共活動應該通過設計來測試其所有的私人活動。 – David

+0

你的代碼不會編譯:)你可以看到你的私有函數populateActionHandlers()被公共方法execute()調用。所以你要麼在測試execute()時測試它,要麼你真的需要單獨測試它,那麼你可能會: a)使用反射,這是我的最愛,但被一些 譴責b)使用powermock等模擬來改變executeActionHandlers邏輯並仍然測試執行() https://code.google。com/p/powermock/wiki/MockPrivate – Praeterii

+0

@Peterterii該代碼是一個例子。我想你可以用公共方法調用一個私有函數。鑑於代碼,我不能直接測試私有方法,而必須使用你的建議,有些博客認爲這是代碼味道。那麼我的設計有什麼問題嗎? – sarmahdi

回答

0

建議不將測試私有方法不應阻止一個留下了私有方法做一個奇怪的設計,而應執行測試只能在具有明確的語義的方法。

私人方法通常是技術幫手。如果底層的數據結構發生變化,它們的語義會發生變化,如果調用的公共方法使用另一種算法來實現相同的目標,它們甚至可以被優化。

我會改寫PROGRAMM以下列方式:

... 
public execute(Action action){ 
    Map<Integer,ActionHandlers> handlerMap = populateActionHandlers(action); 
    executeActionHandlers(handlerMap); 
} 
... 

存儲一個函數的結果轉換成私有字段只從這一領域中的另一個功能是不是線程安全的檢索和難以維護。

然而,這個重構會打破所有(但不是寫)測試你的例子的私有方法,因爲接口被改變。如果你只測試了公共方法,那麼在重構之後所有的測試都是有效的。

我知道少數情況下,測試私有方法就可以了。儘管測試私有方法通常是可以避免的,但我認爲私有狀態的檢查有時是一種更好的選擇,而不僅僅是檢查對象的公共狀態。這種檢查可能不如以前那麼健全(但原因如此),但公共狀態往往不完整,很難斷言。在這兩種情況下,我都使用框架picklock,這使得用戶可以方便地訪問私有方法和字段。

+0

感謝您的回覆。但仍然沒有解決手頭的問題,我需要在調用executeActionHandclers()之前測試處理程序Map是否由populateHandlerMap()正確填充。 – sarmahdi

+0

地圖填充的事實是一個實現細節。您不應該測試映射是否填充,而是在執行階段調用正確的處理程序。如果是這樣,地圖必須已填充。如果填充地圖的副作用是公開方法規範的一部分,則爲地圖編寫一個getter並在調用它之後查詢其內容。我會舉一個例子(也是如何調用私有方法),但這需要一個可編譯的測試對象(Action *可以是接口)。 – CoronA