JUnit5相关内容简介
|
著名的Java单元测试框架Junit 4已经出来很长时间了,当时我发现JUnit 5已经处于测试版,就准备写文章来介绍JUnit 5.不过因为还是测试版,所以有些地方还不太完善,我也有点懒没有好好写。这几天突然想起这事了,在到官网上查看,发现就在9月10日,JUnit 5的正式版终于出来了!那么我就正好把文章重新好好写写,为大家介绍这个最新的JUnit框架。 框架结构 和JUnit 4相比,JUnit 5的结构非常清晰,为自定义插件、IDE测试执行等扩展功能做了很好的支持。这一点从项目结构就可以看出来。 JUnit Platform 这一组的包名是org.junit.platform,从名字就可以看到,这一组的主要功能就是作为测试框架的基础平台。这个包下的模块包含基础API、执行引擎及执行器、基本的命令行执行功能、命令行界面、Maven及Gradle的测试插件等最基本的功能。 JUnit Jupiter Jupiter 是JUnit 5的代号,这个包下的模块包含JUnit 5的主要功能。如果我们要使用JUnit 5,那么必然要包含这一组模块。 JUnit Vintage Vintage 是旧版本JUnit 的代号,这个包下的模块可以让我们在新的JUnit平台上运行旧的JUnit 3 和 4 的测试。 导入类库 在JUnit 5还在测试阶段的时候,官方文档上还有在Maven和Gradle中集成JUnit 5的例子。但是到了正式版,这一部分的内容消失了,仅仅留下两个示例项目的链接,让我们自己参考(复制粘贴)。 使用Maven junit5-maven-consumer 是官方的Maven例子。本来我准备把相关的POM配置贴到这里,但是一看Maven的配置太长了,所以还是算了。如果有需求的话请自己查看这个项目的POM配置。 使用Gradle 如果用Gradle的话,那么这个问题就简单多了。在junit5-gradle-consumer 示例项目中也有比较详细的说明。 首先,Gradle默认不支持JUnit 5,,所以需要启用JUnit Platform Gradle 插件来支持。
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0'
}
}
apply plugin: 'org.junit.platform.gradle.plugin'
然后是关于这个Gradle插件的配置。默认情况下所有的引擎和标签都会被执行。如果你想选择只执行某些引擎和标签的测试,可以取消下面的注释并按照你自己的需求进行修改。当然假如你没有这些高级需求,可以把这一部分删掉。
junitPlatform {
// platformVersion '1.0.0'
filters {
engines {
// include 'junit-jupiter','junit-vintage'
// exclude 'custom-engine'
}
tags {
// include 'fast'
exclude 'slow'
}
// includeClassNamePattern '.*Test'
}
// enableStandardTestTask true
// reportsDir file('build/test-results/junit-platform') // this is the default
// logManager 'org.apache.logging.log4j.jul.LogManager'
}
如果你只需要运行JUnit 5测试,只需要导入下面两个依赖项。JUnit Platform的依赖会自动导入。
dependencies {
testCompile("org.junit.jupiter:junit-jupiter-api:5.0.0")
testRuntime("org.junit.jupiter:junit-jupiter-engine:5.0.0")
}
如果你想在新平台下运行旧的JUnit 3和4测试,需要导入下面的依赖项。
dependencies {
testCompile("junit:junit:4.12")
testRuntime("org.junit.vintage:junit-vintage-engine:4.12.0")
}
编写测试 JUnit 4测试 如果前面都配置好了,现在就可以开始编写测试了。首先先来复习一下旧的JUnit 4测试。
public class JUnit4Test {
@BeforeClass
public static void init() {
System.out.println("Before Class");
}
@AfterClass
public static void clean() {
System.out.println("After class");
}
@Before
public void before() {
System.out.println("Before");
}
@After
public void after() {
System.out.println("After");
}
@Test
public void test1() {
System.out.println("Test 1");
}
@Test
public void test2() {
System.out.println("Test 2");
}
}
使用gradle test等命令执行一下,就会执行这个测试。结果类似于这样。 Before Class Before Test 1 Test 2 After After class JUnit 5测试 让我们来看看等效的JUnit 5测试怎么写。可以看到最明显的变化:首先几个注解被重新命名成更见名知义的名称;另外一点是测试方法不必是公有方法,这样我们可以少敲几下键盘。
public class JUnit5Test {
@BeforeAll
static void beforeAll() {
System.out.println("Before All");
}
@AfterAll
static void afterAll() {
System.out.println("After All");
}
@BeforeEach
void before() {
System.out.println("Before");
}
@AfterEach
void after() {
System.out.println("After");
}
@Test
void test1() {
System.out.println("Test 1");
}
@Test
void test2() {
System.out.println("Test 2");
}
}
编写断言 为了验证测试用例是否正确,我们需要编写一些断言。JUnit 5自带了很多断言,可以帮助我们编写测试用例。而且这些断言都带有可以接受lambda表达式的重载版本,非常适合Java 8使用。当然我个人认为断言还是AssertJ更方便一点。
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.*;
public class AssertionDemo {
@Test
void testAssertion() {
assertEquals(10,10);
assertTrue(true);
assertEquals(100,100,"两个数相等");
assertAll("数字",() -> assertEquals("name","name"),() -> assertEquals(500,500));
assertThrows(InvalidParameterException.class,() -> {
throw new InvalidParameterException();
}
);
int result = assertTimeout(Duration.ofSeconds(5),() -> {
int i = 0,j = 0;
while (i <= 100) {
for (; j <= 100000; j++)
j++;
i++;
}
return i;
});
assertEquals(100,result);
}
}
依赖注入 现在测试类的构造方法和测试方法都可以接受参数了。ParameterResolver接口定义了如何在运行时注入参数的方法。内置的几个可以让我们获取测试用例运行时的信息。 首先是TestInfoParameterResolver。如果方法上有TestInfo类型的实例,JUnit 5框架就会自动注入该实例,这个实例的几个方法可以让我们获取测试类和测试方法的名称、显示名称、标签等信息。
public class DependencyInjectionDemo {
@Test
@DisplayName("依赖注入")
@Tag("test")
void testDisplayName(TestInfo testInfo) {
assertEquals("依赖注入",testInfo.getDisplayName());
assertEquals(Collections.singleton("test"),testInfo.getTags());
}
}
还有RepetitionInfoParameterResolver等内置参数解析器,将在后面介绍。 常用注解 显示名称 我们可以为测试类和测试方法添加自定义的名称,这些名贵会由测试运行器和测试报告所显示。显示名称没有变量名那样的显示,可以是一段包含空格的长字符串,甚至还可以是Emoji表情。
@DisplayName("测试类可以指定显示名称")
public class DisplayNameDemo {
@Test
@DisplayName("测试方法也可以指定显示名称")
void testWithLongDisplayName() {
}
@Test
@DisplayName("显示名称还可以包含表情��")
void testWithDisplayNameWithEmoji() {
}
}
禁用测试 @Disabled注解可以用到测试类或测试方法上,可以禁用对应的测试。
@Disabled
public class DisabledTestDemo {
@Test
//@Disabled
void testDisabled() {
}
}
重复测试 如果需要让某个测试方法运行多次,使用@RepeatedTest注解。
public class RepeatedTestDemo {
@RepeatedTest(10)
void testRepeated10Times() {
}
}
还可以注入一个实例RepetitionInfo,检查当前重复次数和总的重复次数。
public class RepeatedTestDemo {
@BeforeEach
void beforeEach(RepetitionInfo info) {
System.out.printf("%d - %dn",info.getCurrentRepetition(),info.getTotalRepetitions());
}
@RepeatedTest(10)
void testRepeated10Times() {
}
}
附带标签 在前面介绍配置Gradle的时候就说了,在配置中可以选择过滤某些标签的测试。要在代码中给标签也很简单,直接用@Tag注解即可。
@Tag("taggedTest")
public class TagDemo {
@Test
@Tag("taggedTest1")
void testWithTag1() {
}
@Test
@Tag("taggedTest2")
void testWithTag2() {
}
}
嵌套测试 有时候可能需要嵌套测试来表明某些测试之间的包含关系。嵌套测试使用@Nested注解。
@DisplayName("外层测试")
public class NestedDemo {
@Test
void testOuter() {
}
@Nested
@DisplayName("内层测试")
class InnerTestDemo {
@Test
void testInner() {
}
}
}
需要注意只有费静态内部类才能使用Nested注解。另外,由于Java不允许内部类有静态方法,所以也不能有@BeforeAll和@AfterAll注解。如果想要突破这个限制,需要在嵌套内部类上添加@TestInstance(Lifecycle.PER_CLASS)注解,详情参见Test Instance Lifecycle。 IDE支持 虽然现在JUnit 5已经出来了。但是各种工具链的支持还没有跟上。目前只有Intellij IDEA和Eclipse 4.7 (Oxygen)添加了对JUnit 5的支持。所以如果在正式场合的话,使用JUnit 4还是更稳妥一点。 常见问题 区分不同版本间的@Test注解 (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
