从 JUnit 4 迁移到 JUnit 5
最后更新:2024年5月11日
1. 概述
在本教程中,我们将学习如何从 JUnit 4 迁移到最新的 JUnit 5 版本,并概述两种版本之间的差异。
有关使用 JUnit 5 的通用指南,请参阅我们的文章 此处。
2. JUnit 5 的优势
让我们从之前的版本 JUnit 4 开始,它有一些明显的限制
- 单个 jar 库包含整个框架。即使我们只需要特定的功能,我们也需要导入整个库。 在 JUnit 5 中,我们可以获得更多的粒度,并且仅导入所需的内容。
- 在 JUnit 4 中,一次只能运行一个测试运行器(例如SpringJUnit4ClassRunner 或 Parameterized)。 JUnit 5 允许多个运行器同时工作。
- JUnit 4 从未超出 Java 7,错过了 Java 8 中的许多功能。 JUnit 5 充分利用了 Java 8 的特性。
JUnit 5 背后的想法是完全重写 JUnit 4,以便消除这些缺陷中的大部分。
3. 不同之处
JUnit 4 被划分为构成 JUnit 5 的模块
- JUnit Platform – 此模块限定了我们可能感兴趣的所有扩展框架:测试执行、发现和报告。
- JUnit Vintage – 此模块允许与 JUnit 4 甚至 JUnit 3 向后兼容。
3.1. 注解
JUnit 5 对其注解进行了重要的更改。 取代 @org.junit.Test,现在我们需要使用 @org.junit.jupiter.api.Test。
最重要的是,我们不能再使用 @Test 注解来指定期望值。
JUnit 4 中的expected 参数
@Test(expected = Exception.class)
public void shouldRaiseAnException() throws Exception {
// ...
}
现在我们可以使用assertThrows 方法
void shouldRaiseAnException() throws Exception {
Assertions.assertThrows(Exception.class, () -> {
//...
});
}
JUnit 4 中的timeout 属性
@Test(timeout = 1)
public void shouldFailBecauseTimeout() throws InterruptedException {
Thread.sleep(10);
}
现在 JUnit 5 中的assertTimeout 方法
@Test
void shouldFailBecauseTimeout() throws InterruptedException {
Assertions.assertTimeout(Duration.ofMillis(1), () -> Thread.sleep(10));
}
以下是在 JUnit 5 中更改的一些其他注解
- @Before 注解现在是 @BeforeEach
- @After 注解现在是 @AfterEach
- @BeforeClass 注解现在是 @BeforeAll
- @AfterClass 注解现在是 @AfterAll
- @Ignore 注解现在是 @Disabled
3.2. 断言
在 JUnit 5 中,我们也可以在 lambda 中编写断言消息,从而允许延迟评估,直到需要时才跳过复杂的构造消息。
@Test
void shouldFailBecauseTheNumbersAreNotEqual_lazyEvaluation() {
Assertions.assertTrue(
2 == 3,
() -> "Numbers " + 2 + " and " + 3 + " are not equal!");
}
此外,我们可以在 JUnit 5 中组合断言
@Test
void shouldAssertAllTheGroup() {
List<Integer> list = Arrays.asList(1, 2, 4);
Assertions.assertAll("List is not incremental",
() -> Assertions.assertEquals(list.get(0).intValue(), 1),
() -> Assertions.assertEquals(list.get(1).intValue(), 2),
() -> Assertions.assertEquals(list.get(2).intValue(), 3));
}
3.3. 假设
新的Assumptions 类现在位于org.junit.jupiter.api.Assumptions。 JUnit 5 完全支持 JUnit 4 中现有的假设方法,并添加了一组新的方法,允许我们在特定场景下运行某些断言。
@Test
void whenEnvironmentIsWeb_thenUrlsShouldStartWithHttp() {
assumingThat("WEB".equals(System.getenv("ENV")),
() -> assertTrue("http".startsWith(address)));
}
3.4. 标记和过滤
在 JUnit 4 中,我们可以使用@Category 注解对测试进行分组。 在 JUnit 5 中,@Category 注解被@Tag 注解取代
@Tag("annotations")
@Tag("junit5")
class AnnotationTestExampleUnitTest {
/*...*/
}
我们可以使用maven-surefire-plugin 包含/排除特定的标签
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<properties>
<includeTags>junit5</includeTags>
</properties>
</configuration>
</plugin>
</plugins>
</build>
3.5. 运行测试的新注解
在 JUnit 4 中,我们使用 @RunWith 注解来将测试上下文与其他框架集成,或更改测试用例中的整体执行流程。
在 JUnit 5 中,我们现在可以使用 @ExtendWith 注解来提供类似的功能。
例如,要在 JUnit 4 中使用 Spring 功能
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
{"/app-config.xml", "/test-data-access-config.xml"})
public class SpringExtensionTest {
/*...*/
}
在 JUnit 5 中,这是一个简单的扩展
@ExtendWith(SpringExtension.class)
@ContextConfiguration(
{ "/app-config.xml", "/test-data-access-config.xml" })
class SpringExtensionTest {
/*...*/
}
3.6. 新的测试规则注解
在 JUnit 4 中,我们使用 @Rule 和 @ClassRule 注解为测试添加特殊功能。
在 JUnit 5 中,我们可以使用 @ExtendWith 注解重现相同的逻辑。
例如,假设我们在 JUnit 4 中有一个自定义规则,用于在测试之前和之后写入日志跟踪
public class TraceUnitTestRule implements TestRule {
@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
// Before and after an evaluation tracing here
...
}
};
}
}
并且我们在测试套件中实现它
@Rule
public TraceUnitTestRule traceRuleTests = new TraceUnitTestRule();
在 JUnit 5 中,我们可以以更直观的方式编写相同的代码
public class TraceUnitExtension implements AfterEachCallback, BeforeEachCallback {
@Override
public void beforeEach(TestExtensionContext context) throws Exception {
// ...
}
@Override
public void afterEach(TestExtensionContext context) throws Exception {
// ...
}
}
使用 JUnit 5 的 AfterEachCallback 和 BeforeEachCallback 接口,这些接口在 org.junit.jupiter.api.extension 包中可用,我们可以轻松地在测试套件中实现此规则
@ExtendWith(TraceUnitExtension.class)
class RuleExampleUnitTest {
@Test
void whenTracingTests() {
/*...*/
}
}
3.7. JUnit 5 Vintage
JUnit Vintage 通过在 JUnit 5 上下文中运行 JUnit 3 或 JUnit 4 测试来帮助迁移 JUnit 测试。
我们可以通过导入 JUnit Vintage Engine 来使用它
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>${junit5.vintage.version}</version>
<scope>test</scope>
</dependency>
4. 结论
JUnit 5 是 JUnit 4 框架的一个模块化和现代版本。 在本文中,我们介绍了这两个版本之间的主要区别,并暗示了如何从一个版本迁移到另一个版本。
支持本文的代码可在 GitHub 上获取。 一旦你以 Baeldung Pro 会员 身份登录,就开始学习并在项目上进行编码。















