JUnit 5 快速上手(从 JUnit 4 到 JUnit 5)
一直在关注 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 等正常工作。