背景介绍
JUnit是一个开源的单元测试框架,专为Java编程语言设计。它提供了一种简单的机制,使得开发者可以在编写代码时快速创建和运行测试,从而验证程序的逻辑和功能是否按预期工作。JUnit最初是由Erich Gamma和Kent Beck于1997年创建的,最早目的在于支持测试驱动开发(TDD),并为程序测试提供一个标准化的框架。
JUnit的发展历程与Java语言的演进密切相关。随着Java应用的普及,尤其是在企业级应用和大型软件开发项目中,测试的重要性逐渐被认识到。JUnit因其简洁的使用方式和对测试人员友好的设计,使得测试成为了Java开发过程中不可或缺的一部分。
JUnit 4和JUnit 5是推动Java测试开发的两个重要版本。JUnit 4 自2006年发布以来,成为Java开发者的事实标准,因其简单易用和广泛支持而被广泛采用。JUnit 5于2017年推出,旨在改进并增强JUnit的功能,引入了模块化设计、更多注解和灵活性。
JUnit 4:以其稳定性和成熟的生态系统著称,广泛应用于大量现有项目中。
JUnit 5:引入了新的特性,如标签(@Tag)、动态测试、条件测试以及与现代Java特性的更好集成,增强了测试的表达能力与可扩展性。
优缺点
JUnit 4优缺点:成熟、易于使用、社区支持广泛,但在新功能方面缺乏灵活性。
JUnit 5优缺点:具有强大的新特性,如条件测试和动态测试,然而对于新的开发者来说,学习曲线会更陡峭。
对比
在JUnit 5中,许多注解都有所变化和改进,以增强可读性、灵活性和功能。以下是JUnit 4和JUnit 5之间一些重要注解变化的对比:
重要注解变化对比
JUnit 4 | JUnit 5 | 说明 |
---|---|---|
@Before | @BeforeEach | @Before 在每个测试方法执行之前运行,JUnit 5使用@BeforeEach 替代,语义更清晰。 |
@After | @AfterEach | @After 在每个测试方法执行之后运行,JUnit 5用@AfterEach 替代,提升可读性。 |
@BeforeClass | @BeforeAll | @BeforeClass 在所有测试方法之前执行一次,JUnit 5使用@BeforeAll 替代,需为静态方法。 |
@AfterClass | @AfterAll | @AfterClass 在所有测试方法之后执行一次,JUnit 5使用@AfterAll 替代,需为静态方法。 |
@Test | @Test | 这个注解保持不变,JUnit 5继续使用@Test 来标识测试方法。 |
@Ignore | @Disabled | @Ignore 用于跳过测试,JUnit 5用@Disabled 替代,以提供更直观的语义。 |
@Nested | 新增的注解,用于在同一测试类中定义嵌套测试类,方便组织相关的测试用例。 | |
@DisplayName | 新增注解,允许为测试类和方法定义自定义名称,以提升报告的可读性。 | |
@Tag | 新增注解,允许为测试分组,便于选择性执行特定标签的测试。 | |
@ParameterizedTest | 取代JUnit 4的@RunWith(Parameterized.class) ,提供更简洁的参数化测试支持。 | |
@TestInstance | 新增注解,用于配置测试实例的生命周期,可选择PER_CLASS 或PER_METHOD ,改变了测试实例的管理方式。 |
详细描述
-
@Before
vs.@BeforeEach
- JUnit 4:
@Before
用于每个测试方法之前执行,但该名称没有明确说明其作用是“每个”(Each)。标记为@Before的方法将在每个测试运行之前被调用,通常用于设置测试环境或初始化测试所需的对象。 - JUnit 5:
@BeforeEach
清楚地指出这是针对每个测试方法的处理,提升了可读性。
- JUnit 4:
-
@After
vs.@AfterEach
- JUnit 4: 与
@Before
的命名类似,略显模糊。@After
标记的方法会在每个测试方法之后调用,通常用于清理资源或重置状态。 - JUnit 5:
@AfterEach
同样提高了可读性,明确表示其用途。
- JUnit 4: 与
-
@BeforeClass
vs.@BeforeAll
- JUnit 4:
@BeforeClass
在所有测试之前只执行一次,且该方法必须是静态的。标记为@BeforeClass
的方法在该测试类中的所有测试之前执行一次,适合用于昂贵的初始化过程,如数据库连接。 - JUnit 5:
@BeforeAll
与之相同,但提高了语义清晰度,同时要求该方法依旧是静态的。
- JUnit 4:
-
@AfterClass
vs.@AfterAll
- JUnit 4:
@AfterClass
在所有测试之后执行一次。@AfterClass
标记的方法在所有测试执行完后执行,适合用于资源的清理。 - JUnit 5:
@AfterAll
具有相同功能,语义更加明确。
- JUnit 4:
-
@Ignore
vs.@Disabled
- JUnit 4:
@Ignore
令人难以理解其目的。此注解用于暂时跳过特定的测试,方便在需要时不执行该测试。 - JUnit 5:
@Disabled
使用户一目了然,表明此测试被禁用。
- JUnit 4:
-
新增注解
@Nested
: 这个新特性允许在测试类内部创建子类,从而组织相关的测试案例,尤其在需要组合多个测试场景时非常有用。@DisplayName
: 可以为测试类和测试方法指定更具描述性的名称,提高测试报告的可读性。@Tag
: 通过标签系统,开发者可以对测试用例进行分组,并选择性地执行特定组的测试。@ParameterizedTest
: 这一注解比JUnit 4的参数化测试方式更加简洁灵活,允许开发者轻松定义参数化测试的方法。@TestInstance
: 允许开发者更灵活地管理测试实例的生命周期,支持按类或按方法创建实例,方便在测试中共享状态。
执行案例
JUnit 4 与 JUnit 5 混合着使用会出问题,比如会注解混用。
JUnit 4使用示例:
package cn.com.nxg.test.domain;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.*;
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApiTest {
private Map<Integer, Integer> map = new HashMap<>();
@Test
public void test_Method1() {
Integer value = map.get(1);
log.info("我开始执行测试用例了,value:{}",value);
}
// 在每个测试方法之前执行的代码
@Before
public void test_setUp() {
map.put(1, 10001);
log.info("测试方法执行前执行" );
}
}
JUnit 5
package cn.com.nxg.test.domain;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.*;
@Slf4j
@SpringBootTest
public class ApiTest {
private Map<Integer, Integer> map = new HashMap<>();
@Test
public void test_Method1() {
Integer value = map.get(1);
log.info("我开始执行测试用例了,value:{}",value);
}
// 在每个测试方法之前执行的代码
@BeforeEach
public void test_setUp() {
map.put(1, 10001);
log.info("测试方法执行前执行" );
}
}
当你混合使用JUnit 4和JUnit 5中方法时,会报错,如:在JUnit 5中使用JUnit 4注解@Before,而测试方法中使用JUnit 5中的注解@Test,这时,就会出现空指针异常。
回顾
1.使用@Before时是在JUnit 4中,使用@BeforeEach是在JUnit 5中的方法。
2.JUnit 4与JUnit 5对应的方法不能混合使用。
2.JUnit 5对注解的变化不仅提高了代码的可读性和可维护性,也加强了功能性,使得开发者在编写测试时能够更加便利和灵活。
附录
JUnit5 与 JUnit4
JUnit 4迁移到JUnit 5
教你认识Java单元测试框架JUnit,JUnit5和JUnit4区别详解