升級到JUnit5的7個理由

最新版本的JUnit在2017年的第三季度已經發布了final release版本。大量的里程碑改進加入了新版本中。我希望你能夠儘快的使用起來,這篇文章的主題,我列出了7個點,鼓勵大家立刻開始去玩玩JUnit5.

立刻可用
當一門語言、一款應用服務器或代碼庫的新版本出現的時候,大部分開發人員往往會等到業界真正開始推行這個產品的時候,纔開始選擇學習。這種情況經常出現,看看JavaScript,在ES2015規範發佈兩年後,大部分主流Web瀏覽器仍在努力支持所有語言特徵。雖然JS轉化器在一定程度上推動了標準的實施,但是確實是饒了一個彎路。

JUnit5團隊從一開始就考慮了新版本的這些問題。IntelliJ IDEA已經支持IDE中運行JUnit5測試,Eclipse也將支持JUnit5列入了其beta support列表中。兩款最流行的構建工具,Maven和Gradle,已經支持JUnit5測試。如果你不熟悉這些流行的工具,JUnit5也提供了一款控制檯工具幫你自動的運行JUnit5測試。就算這些都不成立,還有一個JUnit4的測試運行工具能夠在JUnit4環境中測試新版本的測試代碼。你看看,所有的配套都準備好了。

易於學習
第一眼看上去,新的API(新命名爲JUnit Jupiter)和他的前身非常像。這個相似程度之高,甚至你會覺得這個新的版本就是新瓶裝舊酒。包括最流行的那些斷言方法也是一樣的。唯一的區別就是放在了不同的包中,並且參數的順序有了一些區別。一些JUnit4中的著名的註解修改了名字,但是作用都是差不多的。如果你對JUnit4比較熟悉,那麼你要掌握JUnit5的基礎使用,只需要幾分鐘。

這個時候,你可能會想,既然兩個版本這麼像,那爲啥我還要升級呢?簡單來說,JUnit5更像是JUnit4的一個超集,他提供了非常多的增強。

全新的功能
一旦你熟悉了JUnit5的基礎內容,你可以順利進入下一個階段,根據你的需求,你可能會考慮以下幾個進階點:

新的斷言
嵌套測試類 - 不僅僅是BDD(Behavior Driven Development)開發人員大力推崇
動態測試 - 在運行時生成測試用例
擴展測試 - 允許你重新定義測試的行爲,允許你使用插件的形式重用你的測試類。
解決了前序版本的問題
沒有完美的東西,JUnit4也一樣。在JUnit4中,在社區中對幾個大大小小的問題都有各種討論和改進,我們來看看這些問題。

異常驗證

異常檢查可以說是JUnit4中一個標誌性的問題。我們來考慮一下下面這個JUnit4測試:

@Test(expected = IllegalArgumentException.class)
public void shouldThrowException() throws Exception {
    Task task = buildTask();
    LocalDateTime oneHourAgo = LocalDateTime.now().minusHours(1);
    task.execute(oneHourAgo);
}

想象我們運行這個測試,如果傳入到execute()方法中的參數是一個過去的時間,會正常拋出一個IllegalArgumentException異常。這種情況下,測試會運行的正確。但是如果在buildTask()方法中拋出一個異常呢?測試會正常執行,並且會提示你得到的異常和期望異常不匹配。這裏,問題就出來了,我們只是希望測試在指定位置得到指定的異常,而不是在整個測試體中出現的異常,都作爲對比異常。在JUnit5中,提供了一個assertThrows()方法,可以非常輕鬆的處理這個問題:

@Test
void shouldThrowException() throws Exception {
    Task task = buildTask();
    LocalDateTime oneHourAgo = LocalDateTime.now().minusHours(1);
    assertThrows(IllegalArgumentException.class,
                 () -> task.execute(oneHourAgo));
}

超時時間測試

額外的,添加了一組新的斷言,用於在lambda樣式斷言中衡量代碼超時時間,在這種情況下,就不會擔心測試的setup階段對代碼執行時間的影響,你可以指定只去衡量某一段代碼的執行時間。另外,還提供了一個選項,當已經出現超時的時候,你是選擇停止應用執行或者是繼續當前測試以衡量代碼執行的真實完整時間。

@Test
void shouldTimeout() throws Exception {
    ExpensiveService service = setupService();
    assertTimeout(ofSeconds(3), () -> {
        service.expensiveMethod();
    });
}

參數化測試

在JUnit4中,如果想要實現參數化測試(使用不同的參數來測試相同的一個方法),只能使用測試類中的字段來實現,在JUnit5中,提供了參數化測試來實現這個需求。不同的參數值可以直接和一個測試方法關聯,並且允許直接在一個測試類中提供不同的參數值直接參與測試,這些在JUnit4中,都是不可能實現的。

測試的參數可以通過一組CSV格式的字符串,外部的CSV文件,枚舉,工廠方法,或者指定的提供類來提供。CSV中的字符串類型的值可以自動的轉化爲指定的類型,並且你可以完成自己的類型轉換器,將String轉成你希望的任何指定類型。

多運行器

JUnit4中最讓人詬病的可能就是不能使用多個測試運行器測試。參數化測試或者嵌套測試的問題,可以通過測試運行器來解決,但問題是我們只能使用一個測試運行器。比如,在Spring4.2之前,每一個依賴於Spring上下文的測試都只能使用SpringJUnit4ClassRunner,在4.2之後,你可以使用專用的規則來(SpringClassRule)處理這個問題,允許你使用不同的測試運行器來運行測試,但是同一時間,仍然只能使用一次。JUnit4從一開始因爲兼容問題,就根本沒有設計運行器擴展的問題。JUnit 5團隊選擇了一條不同的路徑,並計劃了新版本的架構來解決這個問題。

遷移簡單
到這裏,你是否又擔心在目前的項目中已經有上百個測試用例,爲了獲得JUnit5的好處,而不得不重寫這些測試代碼?請放鬆,JUnit5團隊提供了多種升級的選擇。第一點,你可以在一個項目中同時使用JUnit4和JUnit5,而不用擔心出現衝突。當你添加新的JUnit依賴到項目中,有兩種方式可以同時運行測試。

侵略性最小的方式是使用JUnit5 API完成新的測試,並且使用專用的JUnitPlatform運行器在JUnit4下運行。但是,剛纔我們不是才說JUnit4的癥結是運行器麼?當然,這個JUnitPlatform是一個受限的運行器,他只能支持新版本的一部分功能。但是,這仍然是一個開始使用新版本API的不錯的開始。最快的學習方法就是在真實項目中使用,對吧。

第二種方式,是將JUnit5作爲主要的測試運行器。除了能獲取框架帶來的諸多優勢,你也可以在新的平臺中運行老版本的測試,當然有一些限制。由於設計概念上的區別,JUnit4中只有部分的一些特性能夠在JUnit5中運行。在你邁進JUnit5之前,先了解一下這些限制:http://junit.org/junit5/docs/current/user-guide/#migrating-from-junit4-rulesupport

做貢獻的機會
因爲新版本還在持續開發過程中,這個時候提交一些有用的想法,是非常好的機會。框架的使用者,你期望在項目中能用到哪些新的功能,每一個有用的想法都可以通過issue提交到JUnit5項目中。

但是,當你提交一個新的issue的時候,請確保這個想法在框架中確實沒有實現。儘量不要爲團隊開發者去處理已經存在的issue或者沒有太多價值的issue。但是,如果你有一個好的建議,不要猶豫,請提交一個issue。對開源的貢獻一定不是僅僅只侷限於代碼提交,貢獻idea同樣重要。JUnit5的issues列表:https://github.com/junit-team/junit5/issues

JVM測試
JUnit5的目標,不僅僅只是瞄準測試框架。JUnit5的重大改進不僅僅只是打破了常規的API,或者引入了新的擴展模型。一個非常重要的目標,是打造一個基於JVM測試框架的基礎平臺。這意味着什麼?我們來看一個圖:

你可以看到,就像洋蔥一樣,JUnit5的架構也是分層的。最核心的就是基礎平臺。IDE和構建工具都是作爲客戶端和這個核心平臺交互,以達到在項目中運行測試的目的。TestEngine的實現在平臺中用於發現和運行測試,並且輸出測試報告,並通過核心平臺返回給客戶端。

核心關注點是擴展能力,但並不僅僅只是存在於測試類級別。在整個測試平臺級別,都提供了足夠的擴展能力。任何一個框架都可以在JUnit平臺上運行他自己的測試,只需要提供框架本身對TestEngine接口的實現即可。只需要一點點工作,通過這一個擴展點,框架就能得到所有IDE和構建工具在測試上的支持。這對於新框架來說絕對是好事,在測試和構建這塊的門檻更低。

這些對於一個開發者來說意味着什麼呢?這意味着一個測試框架和JVM開發市場上所有主流的工具集成的時候,你能更容易的說服你的經理,開發leader,或者不管是誰阻礙你引入這個測試框架的人。 JUnit Vintage就是一個TestEngine實現,用於執行JUnit4的測試。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章