2012-01-25 91 views
11

因此,我對軟件測試非常陌生,並且正在考慮向我的一個應用程序添加一些測試。我有一個公共方法addKeywords(),它沿途調用私有方法removeInvalidOperations()。這個私有方法調用一個外部的API,並且約有50行代碼。因爲我認爲這是一個有點複雜的方法,所以我想通過調用addKeyword()方法來測試,而不必這樣做。但這似乎不可能(至少不是JUnit)。我想測試一個私有方法 - 我的設計有什麼問題嗎?

我看過的信息表明,測試一個私有方法的願望可能是代碼味道。有些人認爲這可能是一個跡象,應該把這個重構成一個單獨的課堂並公之於衆。此外,還有一些建議,如果您真的需要,可以對生產代碼進行編輯,例如改變私有方法的可見性。

我真的不明白爲什麼我對當前的代碼設計有問題,但也不喜歡編輯我的生產代碼以適合我的測試需求的想法。

正如我所說 - 我是比較新的測試,所以任何幫助,非常感謝。另外,請讓我知道是否有任何進一步的信息可以幫助我解答。

+0

我經常使用的一個快速解決方法是將訪問權限從private改爲默認(package),並且僅對單元測試的package package access進行評論。這是否可接受取決於您的編碼標準以及您信任的程度你的同行程序員要明白,即使包訪問,這種方法也不是「真正的API」。 – user949300

回答

13

我建議重構它。

我所看到的信息表明,測試 私有方法的願望可能是代碼異味。有人建議 它可能是一個跡象,這應該被重構到一個單獨的類 並公開。

你已經在自己的問題中涵蓋了各種各樣的原因並反對它,你似乎很清楚這些論點。但是你有一個看起來相當複雜並涉及外部API的方法。 這是值得自行測試的。removeInvalidOperations()仍然可以是它所在類的私有方法,但它基本上會委託給另一個依賴項。

class YourClass 
{ 
    private OperationRemover remover; 

    public void addKeywords() { 
     // whatever 
     removeInvalidOperations(); 
    } 

    private void removeInvalidOperations() { 
     remover.remove(); 
    } 
} 

這給你能在某個時候取代這種依賴關係,包括能夠測試addKeywords()方法,無需真正將外部API調用,這會使得測試這種方法更容易的好處。例如,OperationRemover可能是一個接口,並且出於測試目的,您只需傳遞一個存根而不是生產中使用的具體版本。至於你的具體版本,你可以爲它編寫測試,而不依賴於你現有類的情況。

我真的不明白爲什麼我有我當前的代碼設計, 一個問題,但同樣不喜歡編輯我的生產代碼,以適應我的 測試需求的想法。

易測試性是一個副作用。從另一個角度來看:你實際做的是讓代碼鬆耦合和可擴展。上面,我們已經將調用從可能需要使用結果的代碼中分離出來。外部API可能會改變。您可能會從一個服務轉到另一個服務,但使用結果的代碼不必在意。該類可以保持不變,只有實際放置調用的類需要被修改(或替換)。

現實世界的例子:今年是2007年,你在美國一家大型金融中心的銀行工作。您的應用程序需要使用帳戶信息。您的代碼可以在銀行內部的某種Web服務中獲得所需的信息,並以其所需的形式進行處理。 2008年,美國金融業陷入崩潰,而你的銀行(即將瀕臨崩潰)被另一家銀行吞併。您的應用程序不會受到影響,除非您現在必須與尚存銀行內已存在的其他API取得帳戶信息。消費此帳戶信息的代碼是否需要更改?不必要。這是與以前相同的帳戶信息,只是來自不同的來源。不,所有需要更改的是調用API的實現。消費代碼永遠不需要知道。

事實上,這種鬆散的耦合也促進和促進測試是一種獎勵。

+0

感謝您的詳細解答!這真的幫助我理解這種方法背後的一些好處。 – QuakerOat

7

如果它是private,它不能被認爲是你的應用程序的API的一部分,所以測試它確實是一種代碼異味 - 當測試中斷時,是否正確?

單元測試應該是功能導向而不是面向代碼。您測試功能的單位,而不是代碼單位。

不管哲學如何,在實現之外的類不能訪問私有方法而不會破壞JVM,所以你運氣不好 - 你必須改變方法的可見性,使protected測試API成爲單元測試類擴展,或通過調用使用它的公共方法來間接測試函數。

0

如果您不想打電話addKeywords()做,也許你應該只添加其他公共方法testRemoveInvalidOperations(),這只是調用私有removeInvalidOperations()。您可以稍後刪除測試。

+0

+1不是一個壞主意。微小的變化:使testRemoveInvalidOperations()默認訪問(包),並添加相關的評論,以澄清它的目的只是單元測試。 – user949300

+0

-1在代碼中鑽空洞只是爲了測試,這絕不是一個好主意。你必須測試你有什麼,而不是你想要什麼。 此外,良好的測試往往要求良好的設計。如果測試希望你重構它,那很可能是正確的。測試一段複雜的代碼並不公平。 – pkoch

+0

無可否認,在向公衆發佈文件之前,您必須確保刪除測試代碼。公開代碼是一個壞主意! – Daniel

4

通常你不想測試一個私有方法,但也有例外。

你可能想測試一個私有方法:

  1. 你還沒有仔細想過如何通過調用現有的公共方法來測試私有方法 間接。

  2. 您班的API太不靈活。公共方法需要更多 參數,或者某些私有方法需要公開。

  3. 你的類的API是不夠靈活,但公衆 方法它的下面有一些很複雜的私有方法回事 下方。

根據你的問題,你可能在任何這些情況下。

對於(1),顯然你應該首先嚐試找到一種方法來測試你的私有方法與現有的公共方法。對於(2)和(3),單元測試不會告訴你你正在使用哪種情況。你需要做的是編寫一些示例代碼。如Josh Bloch recommends,爲您的API編寫一些用例。您的API應該是滿足您的用例所需的最小公共方法。(3)是可以測試私有方法的情況。有各種各樣的tricks for that。對於產品代碼,這些比將您的方法暴露給API用戶(使其公開)更好,以便您可以對其進行測試。或者將相關功能分成兩個類,以便測試它。

而不是根據「代碼氣味」,這是不精確和主觀的思考,你可以考慮information hiding。可能會改變的設計決策不應該暴露在您的公共API中。優選地,可能改變的設計決策不應該暴露於單元測試 - 這就是爲什麼人們建議不要測試私有方法。

但是如果你真的認爲單元測試你的私有方法很重要,並且如果你不能通過公共方法充分做到這一點,那麼不要犧牲代碼的正確性!測試私有方法。最糟糕的情況是你的測試代碼更混亂,並且你必須在私有方法改變時重寫測試。

相關問題