升级到JUnit5的7个理由
翻譯:叩丁狼教育吳嘉俊
“不進(jìn),則退”——約翰·沃爾夫?qū)ゑT·歌德
最新版本的JUnit在2017年的第三季度已經(jīng)發(fā)布了final release版本。大量的里程碑改進(jìn)加入了新版本中。我希望你能夠盡快的使用起來,這篇文章的主題,我列出了7個(gè)點(diǎn),鼓勵(lì)大家立刻開始去玩玩JUnit5.
立刻可用
當(dāng)一門語言、一款應(yīng)用服務(wù)器或代碼庫的新版本出現(xiàn)的時(shí)候,大部分開發(fā)人員往往會(huì)等到業(yè)界真正開始推行這個(gè)產(chǎn)品的時(shí)候,才開始選擇學(xué)習(xí)。這種情況經(jīng)常出現(xiàn),看看JavaScript,在ES2015規(guī)范發(fā)布兩年后,大部分主流Web瀏覽器仍在努力支持所有語言特征。雖然JS轉(zhuǎn)化器在一定程度上推動(dòng)了標(biāo)準(zhǔn)的實(shí)施,但是確實(shí)是饒了一個(gè)彎路。
JUnit5團(tuán)隊(duì)從一開始就考慮了新版本的這些問題。IntelliJ IDEA已經(jīng)支持IDE中運(yùn)行JUnit5測試,Eclipse也將支持JUnit5列入了其beta support列表中。兩款最流行的構(gòu)建工具,Maven和Gradle,已經(jīng)支持JUnit5測試。如果你不熟悉這些流行的工具,JUnit5也提供了一款控制臺(tái)工具幫你自動(dòng)的運(yùn)行JUnit5測試。就算這些都不成立,還有一個(gè)JUnit4的測試運(yùn)行工具能夠在JUnit4環(huán)境中測試新版本的測試代碼。你看看,所有的配套都準(zhǔn)備好了。
易于學(xué)習(xí)
第一眼看上去,新的API(新命名為JUnit Jupiter)和他的前身非常像。這個(gè)相似程度之高,甚至你會(huì)覺得這個(gè)新的版本就是新瓶裝舊酒。包括最流行的那些斷言方法也是一樣的。唯一的區(qū)別就是放在了不同的包中,并且參數(shù)的順序有了一些區(qū)別。一些JUnit4中的著名的注解修改了名字,但是作用都是差不多的。如果你對JUnit4比較熟悉,那么你要掌握J(rèn)Unit5的基礎(chǔ)使用,只需要幾分鐘。
這個(gè)時(shí)候,你可能會(huì)想,既然兩個(gè)版本這么像,那為啥我還要升級呢?簡單來說,JUnit5更像是JUnit4的一個(gè)超集,他提供了非常多的增強(qiáng)。
全新的功能
一旦你熟悉了JUnit5的基礎(chǔ)內(nèi)容,你可以順利進(jìn)入下一個(gè)階段,根據(jù)你的需求,你可能會(huì)考慮以下幾個(gè)進(jìn)階點(diǎn):
- 新的斷言
- 嵌套測試類 - 不僅僅是BDD(Behavior Driven Development)開發(fā)人員大力推崇
- 動(dòng)態(tài)測試 - 在運(yùn)行時(shí)生成測試用例
- 擴(kuò)展測試 - 允許你重新定義測試的行為,允許你使用插件的形式重用你的測試類。
解決了前序版本的問題
沒有完美的東西,JUnit4也一樣。在JUnit4中,在社區(qū)中對幾個(gè)大大小小的問題都有各種討論和改進(jìn),我們來看看這些問題。
異常驗(yàn)證
異常檢查可以說是JUnit4中一個(gè)標(biāo)志性的問題。我們來考慮一下下面這個(gè)JUnit4測試:
@Test(expected = IllegalArgumentException.class) public void shouldThrowException() throws Exception {Task task = buildTask();LocalDateTime oneHourAgo = LocalDateTime.now().minusHours(1);task.execute(oneHourAgo); }想象我們運(yùn)行這個(gè)測試,如果傳入到execute()方法中的參數(shù)是一個(gè)過去的時(shí)間,會(huì)正常拋出一個(gè)IllegalArgumentException異常。這種情況下,測試會(huì)運(yùn)行的正確。但是如果在buildTask()方法中拋出一個(gè)異常呢?測試會(huì)正常執(zhí)行,并且會(huì)提示你得到的異常和期望異常不匹配。這里,問題就出來了,我們只是希望測試在指定位置得到指定的異常,而不是在整個(gè)測試體中出現(xiàn)的異常,都作為對比異常。在JUnit5中,提供了一個(gè)assertThrows()方法,可以非常輕松的處理這個(gè)問題:
@Test void shouldThrowException() throws Exception {Task task = buildTask();LocalDateTime oneHourAgo = LocalDateTime.now().minusHours(1);assertThrows(IllegalArgumentException.class,() -> task.execute(oneHourAgo)); }超時(shí)時(shí)間測試
額外的,添加了一組新的斷言,用于在lambda樣式斷言中衡量代碼超時(shí)時(shí)間,在這種情況下,就不會(huì)擔(dān)心測試的setup階段對代碼執(zhí)行時(shí)間的影響,你可以指定只去衡量某一段代碼的執(zhí)行時(shí)間。另外,還提供了一個(gè)選項(xiàng),當(dāng)已經(jīng)出現(xiàn)超時(shí)的時(shí)候,你是選擇停止應(yīng)用執(zhí)行或者是繼續(xù)當(dāng)前測試以衡量代碼執(zhí)行的真實(shí)完整時(shí)間。
@Test void shouldTimeout() throws Exception {ExpensiveService service = setupService();assertTimeout(ofSeconds(3), () -> {service.expensiveMethod();}); }參數(shù)化測試
在JUnit4中,如果想要實(shí)現(xiàn)參數(shù)化測試(使用不同的參數(shù)來測試相同的一個(gè)方法),只能使用測試類中的字段來實(shí)現(xiàn),在JUnit5中,提供了參數(shù)化測試來實(shí)現(xiàn)這個(gè)需求。不同的參數(shù)值可以直接和一個(gè)測試方法關(guān)聯(lián),并且允許直接在一個(gè)測試類中提供不同的參數(shù)值直接參與測試,這些在JUnit4中,都是不可能實(shí)現(xiàn)的。
測試的參數(shù)可以通過一組CSV格式的字符串,外部的CSV文件,枚舉,工廠方法,或者指定的提供類來提供。CSV中的字符串類型的值可以自動(dòng)的轉(zhuǎn)化為指定的類型,并且你可以完成自己的類型轉(zhuǎn)換器,將String轉(zhuǎn)成你希望的任何指定類型。
多運(yùn)行器
JUnit4中最讓人詬病的可能就是不能使用多個(gè)測試運(yùn)行器測試。參數(shù)化測試或者嵌套測試的問題,可以通過測試運(yùn)行器來解決,但問題是我們只能使用一個(gè)測試運(yùn)行器。比如,在Spring4.2之前,每一個(gè)依賴于Spring上下文的測試都只能使用SpringJUnit4ClassRunner,在4.2之后,你可以使用專用的規(guī)則來(SpringClassRule)處理這個(gè)問題,允許你使用不同的測試運(yùn)行器來運(yùn)行測試,但是同一時(shí)間,仍然只能使用一次。JUnit4從一開始因?yàn)榧嫒輪栴},就根本沒有設(shè)計(jì)運(yùn)行器擴(kuò)展的問題。JUnit 5團(tuán)隊(duì)選擇了一條不同的路徑,并計(jì)劃了新版本的架構(gòu)來解決這個(gè)問題。
遷移簡單
到這里,你是否又擔(dān)心在目前的項(xiàng)目中已經(jīng)有上百個(gè)測試用例,為了獲得JUnit5的好處,而不得不重寫這些測試代碼?請放松,JUnit5團(tuán)隊(duì)提供了多種升級的選擇。第一點(diǎn),你可以在一個(gè)項(xiàng)目中同時(shí)使用JUnit4和JUnit5,而不用擔(dān)心出現(xiàn)沖突。當(dāng)你添加新的JUnit依賴到項(xiàng)目中,有兩種方式可以同時(shí)運(yùn)行測試。
侵略性最小的方式是使用JUnit5 API完成新的測試,并且使用專用的JUnitPlatform運(yùn)行器在JUnit4下運(yùn)行。但是,剛才我們不是才說JUnit4的癥結(jié)是運(yùn)行器么?當(dāng)然,這個(gè)JUnitPlatform是一個(gè)受限的運(yùn)行器,他只能支持新版本的一部分功能。但是,這仍然是一個(gè)開始使用新版本API的不錯(cuò)的開始。最快的學(xué)習(xí)方法就是在真實(shí)項(xiàng)目中使用,對吧。
第二種方式,是將JUnit5作為主要的測試運(yùn)行器。除了能獲取框架帶來的諸多優(yōu)勢,你也可以在新的平臺(tái)中運(yùn)行老版本的測試,當(dāng)然有一些限制。由于設(shè)計(jì)概念上的區(qū)別,JUnit4中只有部分的一些特性能夠在JUnit5中運(yùn)行。在你邁進(jìn)JUnit5之前,先了解一下這些限制:http://junit.org/junit5/docs/current/user-guide/#migrating-from-junit4-rulesupport
做貢獻(xiàn)的機(jī)會(huì)
因?yàn)樾掳姹具€在持續(xù)開發(fā)過程中,這個(gè)時(shí)候提交一些有用的想法,是非常好的機(jī)會(huì)。框架的使用者,你期望在項(xiàng)目中能用到哪些新的功能,每一個(gè)有用的想法都可以通過issue提交到JUnit5項(xiàng)目中。
但是,當(dāng)你提交一個(gè)新的issue的時(shí)候,請確保這個(gè)想法在框架中確實(shí)沒有實(shí)現(xiàn)。盡量不要為團(tuán)隊(duì)開發(fā)者去處理已經(jīng)存在的issue或者沒有太多價(jià)值的issue。但是,如果你有一個(gè)好的建議,不要猶豫,請?zhí)峤灰粋€(gè)issue。對開源的貢獻(xiàn)一定不是僅僅只局限于代碼提交,貢獻(xiàn)idea同樣重要。JUnit5的issues列表:https://github.com/junit-team/junit5/issues
JVM測試
JUnit5的目標(biāo),不僅僅只是瞄準(zhǔn)測試框架。JUnit5的重大改進(jìn)不僅僅只是打破了常規(guī)的API,或者引入了新的擴(kuò)展模型。一個(gè)非常重要的目標(biāo),是打造一個(gè)基于JVM測試框架的基礎(chǔ)平臺(tái)。這意味著什么?我們來看一個(gè)圖:
你可以看到,就像洋蔥一樣,JUnit5的架構(gòu)也是分層的。最核心的就是基礎(chǔ)平臺(tái)。IDE和構(gòu)建工具都是作為客戶端和這個(gè)核心平臺(tái)交互,以達(dá)到在項(xiàng)目中運(yùn)行測試的目的。TestEngine的實(shí)現(xiàn)在平臺(tái)中用于發(fā)現(xiàn)和運(yùn)行測試,并且輸出測試報(bào)告,并通過核心平臺(tái)返回給客戶端。
核心關(guān)注點(diǎn)是擴(kuò)展能力,但并不僅僅只是存在于測試類級別。在整個(gè)測試平臺(tái)級別,都提供了足夠的擴(kuò)展能力。任何一個(gè)框架都可以在JUnit平臺(tái)上運(yùn)行他自己的測試,只需要提供框架本身對TestEngine接口的實(shí)現(xiàn)即可。只需要一點(diǎn)點(diǎn)工作,通過這一個(gè)擴(kuò)展點(diǎn),框架就能得到所有IDE和構(gòu)建工具在測試上的支持。這對于新框架來說絕對是好事,在測試和構(gòu)建這塊的門檻更低。
這些對于一個(gè)開發(fā)者來說意味著什么呢?這意味著一個(gè)測試框架和JVM開發(fā)市場上所有主流的工具集成的時(shí)候,你能更容易的說服你的經(jīng)理,開發(fā)leader,或者不管是誰阻礙你引入這個(gè)測試框架的人。 JUnit Vintage就是一個(gè)TestEngine實(shí)現(xiàn),用于執(zhí)行JUnit4的測試。
相信以上的點(diǎn),足以說服你,開始從一個(gè)新的測試類開始,使用JUnit5。
原文:http://dolszewski.com/testing/7-reasons-why-you-should-start-using-junit-5-today/
?
總結(jié)
以上是生活随笔為你收集整理的升级到JUnit5的7个理由的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 给你三个必须要学C语言的理由!
- 下一篇: 长沙理工大学ACMore编程协会2018