了解JUnit的Runner架构
幾周前,我開始創建一個小的JUnit Runner( Oleaster ),它允許您使用Jasmine方式在JUnit中編寫單元測試。 我了解到,創建自定義JUnit Runners實際上非常簡單。 在本文中,我想向您展示JUnit Runner在內部如何工作以及如何使用自定義Runner來修改JUnit的測試執行過程。
那么什么是JUnit Runner?
JUnit Runner是擴展JUnit抽象Runner類的類。 運行程序用于運行測試類。 可以使用@RunWith注釋設置應該用于運行測試的Runner 。
@RunWith(MyTestRunner.class) public?class?MyTestClass?{@Testpublic?void?myTest()?{..} }JUnit測試是使用JUnitCore類開始的。 可以通過從命令行運行它,也可以使用其各種run()方法之一來完成此操作(如果您按run test按鈕,這就是您的IDE所做的事情)。
JUnitCore.runClasses(MyTestClass.class);然后,JUnitCore使用反射為通過的測試類找到合適的Runner。 此處的一個步驟是在測試類上查找@RunWith批注。 如果未找到其他運行程序,則將使用默認運行程序( BlockJUnit4ClassRunner )。 將實例化Runner,并將測試類傳遞給Runner。 現在,實例化并運行通過的測試類是Runner的工作。
跑步者如何工作?
讓我們看一下標準JUnit Runners的類層次結構:
Runner是一個非常簡單的類,實現了Describable接口,并具有兩個抽象方法:
public?abstract?class?Runner?implements?Describable?{public?abstract?Description?getDescription();public?abstract?void?run(RunNotifier?notifier); }方法getDescription()從Describable繼承,并且必須返回Description 。 描述包含了各種工具以后導出和使用的信息。 例如,您的IDE可能會使用此信息來顯示測試結果。 run()是一種非常通用的方法, 可以運行某些內容 (例如測試類或測試套件)。 我認為通常Runner并不是您要擴展的類(它太慷慨了)。
在ParentRunner中,事情變得更加具體。 ParentRunner是具有多個子代的Runner的抽象基類。 在這里重要的是要理解,測試是按層次結構(例如樹)構造和執行的。
例如:您可能運行包含其他測試套件的測試套件。 這些測試套件可能包含多個測試類。 最后,每個測試類可以包含多個測試方法。
ParentRunner具有以下三種抽象方法:
public?abstract?class?ParentRunner<T>?extends?Runner?implements?Filterable,?Sortable?{????protected?abstract?List<T>?getChildren();protected?abstract?Description?describeChild(T?child);protected?abstract?void?runChild(T?child,?RunNotifier?notifier); }子類需要在getChildren()中返回泛型T的列表。 然后,ParentRunner要求子類為每個孩子(describeChild())創建一個Description,最后運行每個孩子(runChild())。
現在,讓我們看一下兩個標準的ParentRunners:BlockJUnit4ClassRunner和Suite。
如果未提供其他Runner,則使用BlockJUnit4ClassRunner為默認Runner。 因此,這是運行單個測試類時通常使用的Runner。 如果您查看BlockJUnit4ClassRunner的來源,您將看到類似以下內容:
public?class?BlockJUnit4ClassRunner?extends?ParentRunner<FrameworkMethod>?{@Overrideprotected?List<FrameworkMethod>?getChildren()?{//?scan?test?class?for?methonds?annotated?with?@Test}@Overrideprotected?Description?describeChild(FrameworkMethod?method)?{//?create?Description?based?on?method?name}@Overrideprotected?void?runChild(final?FrameworkMethod?method,?RunNotifier?notifier)?{if?(/*?method?not?annotated?with?@Ignore?*/)?{//?run?methods?annotated?with?@Before//?run?test?method//?run?methods?annotated?with?@After}} }當然,這被過度簡化了,但是它說明了BlockJUnit4ClassRunner的基本功能。 通用類型參數FrameworkMethod基本上是java.lang.reflect.Method的包裝,提供了一些方便的方法。 在getChildren()中,掃描測試類以查找使用@Test進行反射的方法。 找到的方法包裝在FrameworkMethod對象中并返回。 describeChildren()從方法名稱創建一個Description,然后runChild()最終運行測試方法。 BlockJUnit4ClassRunner在內部使用了很多受保護的方法。 根據您要確切執行的操作,最好檢查BlockJUnit4ClassRunner中可以覆蓋的方法。 您可以在GitHub上查看BlockJUnit4ClassRunner的源代碼。
Suite Runner用于創建測試套件。 套件是測試(或其他套件)的集合。 一個簡單的套件定義如下所示:
@RunWith(Suite.class) @Suite.SuiteClasses({MyJUnitTestClass1.class,MyJUnitTestClass2.class,MyOtherTestSuite.class }) public?class?MyTestSuite?{}通過選擇帶有@RunWith批注的Suite Runner來創建測試套件。 如果查看Suite的實現,您會發現它實際上非常簡單。 Suite唯一要做的就是從使用@SuiteClasses批注定義的類中創建Runner實例。 因此,getChildren()返回Runners列表,runChild()將執行委托給相應的Runner。
例子
使用提供的信息,創建您自己的JUnit Runner并不難(至少我希望如此)。 如果您正在尋找一些示例自定義Runner實現,則可以查看以下列表:
- Fabio Strozzi創建了一個非常簡單明了的GuiceJUnitRunner項目 。 它使您可以選擇在JUnit測試中注入Guice組件。 來源GitHub
- Spring的SpringJUnit4ClassRunner可幫助您測試Spring框架應用程序。 它允許您在測試類中使用依賴項注入或創建事務性測試方法。 來源GitHub
- Mockito為自動模擬初始化提供了MockitoJUnitRunner 。 來源GitHub
- Oleaster的 Java 8茉莉花賽跑者。 源自GitHub (無恥的自我推廣)
結論
JUnit Runners具有高度可定制性,可讓您選擇更改以完成測試執行過程。 很酷的事情是,可以更改整個測試過程,并且仍然使用IDE,構建服務器等的所有JUnit集成點。
如果您只想進行較小的更改,那么最好查看一下BlockJUnit4Class運行程序的受保護方法。 您很有可能在正確的位置找到可重寫的方法。
翻譯自: https://www.javacodegeeks.com/2014/08/understanding-junits-runner-architecture.html
總結
以上是生活随笔為你收集整理的了解JUnit的Runner架构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 出租房屋不备案(出租房不备案违法吗)
- 下一篇: 男生美白的最快方法 男生美白小窍门