2011-08-02 44 views
63

誰擁有針對該共同需求的解決方案。註釋使私有方法只針對測試類別公開

我在我的應用程序中有一個類。

一些方法是公開的,因爲它們是API, 的一部分,有些是私人的,因爲它們在內部使用使內部流程更加易讀

現在,說我想要寫一個單元測試,或者更像是一個集成測試,它將位於不同的包中,允許調用此方法,但是,如果您嘗試從應用程序的類調用此方法,則不會允許對此方法進行正常調用本身

所以,我在想這樣的事情

public class MyClass { 

    public void somePublicMethod() { 
    .... 
    } 

    @PublicForTests 
    private void somePrivateMethod() { 
    .... 
    } 
} 

上面的註釋將私有方法標記爲「public for tests」 這意味着編譯和運行時將被允許用於任何在測試...包下的類,而編譯和\或運行時將失敗任何不在測試包內的類。

有什麼想法? 有沒有像這樣的註釋? 有沒有更好的方法來做到這一點?

看來你寫更多的單元測試,將更多的inforced打破你的封裝...

+0

爲什麼不使用反射來訪問私有方法? – chance

回答

3

Testing Private Methods的一篇文章列舉了一些方法來測試私有代碼。使用反射會給程序員帶來額外的負擔,要記住重構是否完成,字符串不會自動更改,但我認爲這是最簡潔的方法。

89

的常用方法是使私有方法保護或包私有,並把這個方法的單元測試與被測試的類相同。番石榴有@VisibleForTesting annotation,但它僅用於文件目的。

+9

+1使用相同的包 –

+14

如果你使用FindBugs,我已經爲你構建了一個[可以實際驗證的插件](https://github.com/Monits/findbugs-plugin),這個'@ VisibleForTesting'方法是不在測試課外使用。 – Johnco

10

考慮使用接口來公開API方法,使用工廠或DI來發布對象,以便消費者僅通過接口瞭解它們。該接口描述了已發佈的API。這樣你就可以在實現對象上做任何你想公開的東西,而它們的消費者只能看到通過接口公開的那些方法。

1

你不能這樣做,那麼你怎麼能編譯你的測試呢?編譯器不會考慮註釋。

一般有兩種方法可供選擇

首先是使用反射來訪問這些方法反正

第二個是使用包私人的,而不是私人的,然後讓你的測試在同一個包(但在不同的模塊中)。他們基本上對其他代碼是私有的,但是你的測試仍然可以訪問它們。

當然,如果您進行黑盒測試,您不應該訪問私有成員。

14

如果您的測試覆蓋率的測試類內的所有公共方法好,私處方法由公衆一個叫會被自動測試,因爲你將斷言所有可能的情況。

JUnit的醫生說:

測試私有方法可能是一個跡象,這些方法應該被移動到另一個類,以促進可重用性。 但是,如果您必須... 如果您使用JDK 1.3或更高版本,則可以使用反射來藉助PrivilegedAccessor來破壞訪問控制機制。有關如何使用它的詳細信息,read this article.

2

或者你也可以提取這種方法在一定戰略對象。在這種情況下,您可以輕鬆地測試提取的類,並且不會使方法成爲公共的或帶有反射/字節碼的某些魔法。

0

據我所知,沒有像這樣的註釋。最好的方法是像其他人所建議的那樣使用反射。看看這篇文章:
How do I test a class that has private methods, fields or inner classes?

你應該只注意測試方法的異常結果。例如:如果你期望一個IllegalArgumentException,但是你會得到「null」(Class:java.lang.reflect.InvocationTargetException)。
我的colegue建議使用powermock framework這些情況,但我還沒有測試過,所以不知道它到底能做什麼。儘管我已經使用了基於它的Mockito框架,並且這也是一個很好的框架(但我認爲不能解決私有方法異常問題)。

它雖然具有@PublicForTests標註一個偉大的想法。

乾杯!

4

dp4j有你所需要的。基本上你所要做的就是將dp4j添加到你的類路徑中,並且每當用@Test註解的方法(JUnit的註解)調用一個私有的方法時,它將工作(dp4j將在編譯時注入所需的反射)。您也可以使用dp4j的@TestPrivates註釋來更加明確。

如果你堅持也標註您的私有方法你可以使用谷歌的@VisibleForTesting註解。

1

我們最近發佈了一個庫,幫助了很多通過反射來訪問私有字段,方法和內部類:BoundBox

對於像

public class Outer { 
    private static class Inner { 
     private int foo() {return 2;} 
    } 
} 

類它提供了一種語法,如:

Outer outer = new Outer(); 
Object inner = BoundBoxOfOuter.boundBox_new_Inner(); 
new BoundBoxOfOuter.BoundBoxOfInner(inner).foo(); 

創建BoundBox類必須要做的唯一事情就是編寫@BoundBox(boundClass=Outer.class),並且BoundBoxOfOuter類將立即生成。

1

好的,所以在這裏我們有兩件事情正在混合。首先,當你需要標記某些東西只用於測試時,我同意@JB Nizet,使用番石榴標註會很好。

不同的是,測試私有方法。爲什麼你應該從外部測試私人方法?我的意思是,你應該能夠通過公共方法來測試這個對象,並且最終它的行爲。至少,我們正在努力並試圖教授初級開發人員,他們總是試圖測試私人方法(作爲一種良好做法)。

相關問題