一直在關注 JUnit 5 的演進,自兩年前首個 ALPHA 版后,經歷了 6 的 Milestone, 3 個 RC 終於在 2017/09/10 正式發布了。其實還從未對其深究過,今天算是正式開始體驗。
不像以往的版本,JUnit 5 現在是三個模塊的合體 JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
- JUnit Platform: 運行測試的基礎平台。還定義了開發測試框架的 TestEngine API。並提供了命令行執行測試以及與 Gradle, Maven, JUnit4 Runner 的集成
- JUnit Jupiter: 包含了新的編程和擴展模型。它還提供了一個運行新型測試的 TestEngine 實現
- JUnit Vintage: 提供了一個讓 JUnit Platform 運行 JUnit 3 和 JUnit 4 的 TestEngine 實現
以上三個模塊分工還是很明確,因此
- 從現有的 JUnit 4 項目步入到 JUnit 5 至少兩 JUnit Platform 和 JUnit Vintage 兩個
- 建立全新項目可以只引入 JUnit Platform 和 JUnit Jupiter
- 混合型當然是三個全部引入
但是由於 jar 包之間本身存在某種依賴關系,所以實際上 pom.xml 可以比想像的更簡單
JUnit 5 要求 Java 8 及以上的版本,甚至與 Java 9 也有所展望,這個對於怕出亂子的領導是很難的。
關於 Maven 中如何使用 JUnit 5,可以參考 junit5-maven-consumer 這個 pom.xml 配置; 還可以酌情對該配置進行裁剪。
舉例說明:
- 全新項目,只有 JUnit 5 新型編程/擴展模型,pom.xml 中只需要依賴
123456<dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>5.0.0</version><scope>test</scope></dependency> - 只需讓原來的 JUnit 4 在 JUnit 5 平台上運行的話,pom.xml 中只需要依賴
123456<dependency><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId><version>4.12.0</version><scope>test</scope></dependency>junit-vintage-engine 會自動引入相應版本的 JUnit。當然,如果只是這種需求話,真是吃飽了撐着
- 從 JUnit 4 遷移到 JUnit 5, 這是最貼合實際的需求,此時 pom.xml 只的依賴就是同時需要以上兩個
依賴配置好了,在目前最新的 IntelliJ IDEA 2017.2.4 中可以正常同時執行 JUnit 4 和 JUnit 5 的測試用例了。但目前為止 mvn test
命令只會測試 JUnit 4 的測試用例,若要讓 Maven 識別出所有的測試用例還得加上一個構建插件配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<includes>
<include>**/Test*.java</include>
<include>**/*Test.java</include>
</includes>
<properties>
<!-- <includeTags>fast</includeTags> -->
<excludeTags>slow</excludeTags>
<!--
<configurationParameters>
junit.jupiter.conditions.deactivate = *
</configurationParameters>
-->
</properties>
</configuration>
<dependencies>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-surefire-provider</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
|
關鍵是 junit-platform-surefire-provider
的配置,其他部分只需注意 JUnit 5 可用 @Tag
來標識,包含或排除測試用例。現在 Maven 上也沒問題了。
現在可以來個兼具 JUnit 4 和 JUnit 5 具體來個例子,pom.xml 中需要加上前面提到了三塊配置。下面開始列出代碼
待測試類 Calculation
1
2
3
4
5
6
7
8
|
package cc.unmi;
public class Calculation {
public int add(int first, int second) {
return first + second;
}
}
|
JUnit 4 測試類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
package cc.unmi;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class CalculationTest {
@Test
public void onePlugTwoShouldBeThree() {
Calculation calc = new Calculation();
assertEquals(3, calc.add(1, 2));
}
}
|
JUnit 5 測試類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package cc.unmi;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CalculationJunit5Test {
@Test
@DisplayName("1 plus 2 should be 3")
public void onePlugTwoShouldBeThree() {
Calculation calc = new Calculation();
assertEquals(3, calc.add(1, 2));
}
@Test
@Tag("slow")
public void slow(){
}
}
|
注意:是 JUnit 4 測試類還是 JUnit 5 測試類,關鍵看注解 @Test
是來自於哪個包,比如說
- @Test 是 org.junit.Test,那么它是老的 JUnit 4 的測試類(也可能是 JUnit 3 的)
- @Test 是 org.junit.jpiter.api.Test, 那么它是 JUnit 5 的測試類
@Test
注解的出處會影響其他標簽的行為,例如用 @org.junit.Test
搭配 JUnit 5 特有注解(像 @DisplayName
) 就是來到搗亂的,那么這時候 @DisplayName
不會有任何效果。但 JUnit 4 的 @Test 與新的斷言方法是可以工作的。
如果我們不得不在一個項目中混合 JUnit 4 和 JUnit 5 的話,我們必須保持使用的 API 是版本一致的。
現在我們可以開始運行測試用例了,分別是在 IDE 和控制台下
Intellij IDEA 2017.2.4
IDEA 可以正確處理 @DisplayName 標簽,但是對 @Tag 視而不見
Maven 控制台
Maven 能夠根據 @Tag 進行排除用例,但是它在一切正常時原本就不會顯示測試用類名,所以也就不知道 @DisplayName 是什么,除非自定義 RunListener.
那么 Maven 在有用例失敗時,以往都是顯示失敗的方法名稱,那么 JUnit 5 是怎么顯示失敗的測試用例呢?還是照舊
或許 JUnit 5 還是認為顯示失敗的實際方法名更有助於定位錯誤。因此,基本上認為 @DisplayName 是給 IDE 用的。要不就自定義 RunListener 吧。
本來想在此了解一下 JUnit 5 的新特性,思考之后還是覺得目前最緊要的可能是如何從 JUnit 4 遷移到 JUnit 5, 所以才有了上面的內容。我們完全可以先讓兩個版本的 JUnit 測試用例並行,然后逐步替換掉 JUnit 4 測試用例。官方的遷移文檔是 Migrating from JUnit 4. 遷移不光是 API 的替換,還有 JUnit 5 不再支持 Rule 了,還要驗證 JUnit 5 是否能與 Mock 框架 Mockito, JMockit 等正常工作。