Part 2: 使用 JUnit 5

整合建置工具與 IDE 執行第五版及先前版本的測試

Du Spirit
Java Magazine 翻譯系列
9 min readJul 19, 2020

--

Translated from “Part 2: Using JUnit 5”, Mert Çalişkan, Java Magazine November/December 2016, page 20. Copyright Oracle Corporation.

在本文的第一部分,我提到 JUnit 5 將推出的新功能,接下來我提供更多關於框架的細節,以及與像 Maven 及 Gradle 等建置工具的整合。

本文所有的範例都基於 JUnit 5.0.0-M2,可以從專案首頁取得。

架構概要

我們從 Junit 的套件 (package) 結構開始,該結構在第一次 alpha 釋出後有做調整,JUnit 5 現在主要有 PlatformJupiterVintage 三個套件。目前的版本 M2,套件結構與模組如 Listing 1 所示 [譯註:翻譯時已經釋出 M3 了,搬到 Medium 時已經是 5.6,參閱拙譯《JUnit 5.6 新功能讓測試變簡單》]。

Figure 1. The JUnit 5 architecture

JUnit Platform 套件是 Vintage 與 Jupiter 套件的基礎,它包含 junit-platform-engine 模組,該模組提供公開的 API 以整合第三方測試框架 (像是 Specsy,一個 JVM 語言用的 BDD 風格測試框架);junit-platform-launcher 模組提供啟動 API,讓建置工具與 IDE使用,在第五版之前,IDE 與測試程式碼都使用相同的 JUnit,新版以更加模組化的方式,提供良好的關注點分離,建置工具相關的程式與 API 分開於不同的模組。

junit-platform-runner 模組提供 API 讓 JUnit 5 的測試能在 JUnit 4 上執行;junit-platform-console 模組支援從終端機啟動 JUnit platform,能用命令列的方式執行 JUnit 4 及 JUnit 5 的測試,並傳回測試結果顯示於終端機中; junit-platform-surefire-provider 模組提供的 JUnitPlatformProvider 類別,與 Surefire (Surefire 是 Maven 測試週期中執行 JUnit 的 plug-in) 整合,可以透過 Maven 執行 JUnit 5 的測試;此外,junit-platform-gradle-plugin 模組提供與 Gradle 建置工具的整合,稍後會提到。

JUnit Vintage 套件提供能在 JUnit 5 上執行 JUnit 3 與 JUnit 4 測試的引擎,junit-vintage-engine 模組即是執行測試的引擎,JUnit 團隊支援先前的版本,鼓勵目前不管使用哪個版本的開發者升級到 JUnit 5,稍後我會描述如何執行 JUnit 4 的測試。

JUnit Jupiter 包裝新的 API 及擴充模型,還提供執行 JUnit 5 測試的引擎。junit-jupiter-apijunit-jupiter-engine 是此專案的兩個模組。如果您只宣告相依於 junitjupiter-engine 模組,就足以執行 JUnit 5 的測試,因為 junit-jupiter-apijunit-jupiter-engine 的上游模組 (可轉移相依,transitive dependency)。

配置工具以使用 JUnit 5

可以在 Maven 與 Gradle 中定義對 JUnit 5 的相依,此外,也可以直接透過終端機直接執行測試,有些 IDE 已經開始提供支援執行 JUnit 5 的測試,所以對於新框架的採用情況,看來是樂觀的。

與 Maven 的整合 在 Maven 中定義對 JUnit 5 的相依性就如 Listing 1 所示,如同先前提到的,不需要宣告相依於 junit-jupiter-api 模組,因為當我宣告相依 junit-jupiter-engine 時,它會被當成上游模組而自動抓取。

Listing 1

若您想停留在 JUnit 4.x,是可以加入 vintage 模式的相依性來使用 JUnit 5,如 Listing 2 所示。

Listing 2

當宣告 vintage 模式時,JUnit 4.12 與 junit-platform-engine 會被當成上游模組自動抓取,方便起見,JUnit 團隊對齊 vintage 模組與目前 JUnit 最新的正式版本,寫本文時正是 4.12 版 [譯註:5.0.0 M3 仍然對齊 JUnit 4.12],在宣告完相依性後,該開始使用這些相依的模組來執行您的測試了,在 Maven 的建置週期設定中,如 Listing 3 所示,於 maven-surefire-plugin 的相依性裡加入 junit-platform-surefire-provider

Listing 3

JUnit 團隊開發 junit-platform-surefire-provider 協助透過 Surefire 的機制執行 JUnit Vintage 與 JUnit Jupiter 的測試,這目前還未支援 Surefire 進階的參數,像是 forkCountparallel,但我相信接下來的幾個改版,Surefire 會補足這落差,百分之百支援 JUnit 5。

與 Gradle 的整合 在 Gradle 中定義相依性和 Maven 類似,如 Listing 4 所示,在 Gradle 中加入 Jupiter 引擎與 API 的相依。

Listing 4

若是要加入 Vintage 引擎,則如 Listing 5 所示。

Listing 5

要讓 JUnit Gradle plug-in 加到建置中,如 Listing 6 所示,需宣告並套用到配置檔中。

Listing 6

Listing 7 所示,可以在 junitPlatform 指令中設定 JUnit Gradle plugin,像是我可以定義用來執行的引擎 (預設是全部開啟)、要納入或排除的標籤、設定名稱策略過濾要執行的測試類別、指定特定的報表輸出目錄,以及日誌管理員的設定。

Listing 7

與終端機的整合 命令列應用程式 ConsoleLauncher 讓您可以直接在終端機中執行 JUnit Platform,這程式可以像 Listing 8 般以指令啟動,建立所需 JAR 檔的類別路徑是必要的,所以確保您有正確版本的檔案。

Listing 8

參數 -a 指執行所有測試,參數 -n 指定只執行類別全名 [譯註:包含 package 名稱] 滿足特定正規表示是的測試,雖然根據文件的說法,還可能變動,但仍有許多選項可以使用。

與 IDE 的整合 市面上的 Java IDE 快速地演進,為執行 JUnit 5 測試提供穩健的支援,在寫本文的時候,IntelliJ IDEA 目前的版本可以處理 JUnit 5 的測試,且以樹狀結構分別呈現 Jupiter 及 Vintage 的測試,Figure 2 顯示測試一連串 stack 操作的輸出例子,該測試類別中包含用新的 @Nested 加註的子測試類別,因此開啟建立巢狀的測試,並正確呈現在圖中。

Figure 2. Output from IntelliJ for nested tests

JUnitPlatform 的協助下,讓 JUnit 5 的測試能在 IDE 的 JUnit 4 平台上執行,Eclipse Neon 及 NetBeans 8.1 同樣支援執行 JUnit 5 的測試。

Vintage 模式提供向下相容

JUnitPlatform 類別是 JUnit 4 執行器的一個實作,有它的協助,JUnit Jupiter 的測試可以在 JUnit 4 上執行, JUnitPlatform 類別由 junitplatform-runner 模組提供,所以如 Listing 9 所示,要在 Maven 中加入對 Jupiter engine 的相依。

Listing 9

Listing 10 提供一個簡單的測試類別實作,可以看到 import 的宣告,測試類別是以 JUnit 5 實作,但宣告的執行器,讓它可以在 JUnit 4 的平台上執行,例如 Eclipse Neon。

譯註:其實 Vintage 做蠻多事的,讓我在翻譯時,一直懷疑自己是不是搞錯意思了,但到官網查閱之後,確定沒有翻錯,它可以讓 JUnit 3 和 JUnit 4 的測試在不修改的情況下,能在 JUnit 5 (也就是 Jupiter) 上執行,同時,也可在 JUnit 4 上執行 JUnit 5 的測試 (須加上@RunWith(JUnitPlatform.class)),讓還未支援 JUnit 5 的 IDE 能以 JUnit 4 執行測試 (但不支援某些功能)。

結論

JUnit 團隊在 JUnit 最近的釋出有相當出色表現,新的套件結構可以看出整個框架被翻新,為接下來的釋出提供一個基礎,JUnit 5 幾乎解決了前個版本的所有限制,並提供建置工具、IDE 與第三方測試框架更好的整合支援,在善用 lambda 及新的擴充模型實作下,我相信 JUnit 仍會是最受歡迎的 Java 框架。

learn more
In-depth blog on the JUnit architecture
Using JUnit 5 in IntelliJ IDEA
JUnit team on Twitter

JUnit 5 特刊系列索引
Part 1: Unit 5 初探
深入探討 JUnit 5 的擴充模型
訪談 Kent Beck
“ Mutation Testing: Automate the Search for Imperfect Tests,” page 43

譯者的告白
我還記得研究所 Pattern-oriented Software Design 的後半段,就是拿 JUnit 的架構與程式作為例子,學習 design pattern 如何應用在軟體設計中,當時還是 JUnit 3 的時代,沒想到再次看 JUnit 的架構介紹已經是 JUnit 5 了。話說,每次從 PDF 複製文字時,fi 的 f 就是會不見,所以 define 會變成 deine,Surefire 會變成 Sureire,若是要被翻譯的字也就算了,但像 Surefire 這種保留下來的名字,都還要檢查 f 是否不見了。

--

--