发布于 2026-01-06 1 阅读
0

为什么你应该开始使用 JUnit 5 显示名称 嵌套测试 扩展 从 4 迁移到 5 结论

为什么你应该开始使用 JUnit 5

显示名称

嵌套测试

扩展

从4到5的迁移

结论

本文转载自我的博客,您可以在这里找到原文。

什么是 JUnit 5?

根据其网站信息

JUnit 5 是 JUnit 的下一代版本。其目标是为 JVM 上的开发者端测试创建一个最新的基础架构。这包括重点支持 Java 8 及更高版本,并支持多种不同的测试风格。

本文面向所有听说过或没听说过 JUnit 5,并想知道为什么要使用它的人。

我不想详细介绍所有功能或其内部工作原理,我只想展示一些目前对我来说最有价值的新功能。

那么,让我们直接进入正题……

显示名称

在之前的 JUnit 中,测试用例的名称来源于它们的测试方法。

例如:

    public class AccountTest {

        @Test
        public void testMethod() {
            // do some tests here
        }
    }
Enter fullscreen mode Exit fullscreen mode

运行后,它会输出testMethod测试名称,但这可能没什么用,更重要的是,它难以阅读。测试应该易于理解,因为测试是唯一不会被弃用的真正代码文档。因此,人们开始尝试提出一些更具描述性的测试名称。

    public class AccountTest {

        @Test
        public void withdrawSomeAmountGreaterThanCurrentBalanceFailsWithException() {
            // do some tests here
        }
    }
Enter fullscreen mode Exit fullscreen mode

好些了吗?倒也未必。至少它能让你大致了解接下来会发生什么。大概就是从账户中提取超过当前余额的金额。这应该会失败。但如何让它更易读呢?一些开发者(包括我自己)开始打破 Java 严格的驼峰命名约定,转而使用下划线来分隔测试的不同部分,例如method__scenario__expectedResult

    public class AccountTest {

        @Test
        public void withdraw__amountGreaterThanCurrentBalance__failsWithException() {
            // do some tests here
        }
    }
Enter fullscreen mode Exit fullscreen mode

虽然这种写法更易读一些,但对于习惯驼峰命名法的Java开发者来说,读起来会很别扭。你真正想要的是使用任意字符串作为测试名称。

Kotlin 允许你使用字符串字面量,例如:

    internal class AccountTest {

        @Test
        fun `should thrown an exception when an amount is withdrawn greater that the current balance`() {
            // do some tests here
        }
Enter fullscreen mode Exit fullscreen mode

JUnit 5 来​​帮忙了。虽然不如 Kotlin 那么简单,但 JUnit 5 提供了一个@DisplayName注解,可以用于测试类和方法。缺点是,你仍然需要为方法命名:

    @DisplayName("An account")
    class AccountTest {

        @Test
        @DisplayName("should throw an exception when an amount is withdrawn greater that the current balance")
        void withdrawBalanceExceeded() {
            // do some tests here
        }
    }
Enter fullscreen mode Exit fullscreen mode

所以,尽管出现了典型的 Java 注解混乱,但结果(如 IDE 显示的内容)却更易于阅读。

请注意,您不再需要使用public方法和类。

嵌套测试

在和同事结对编程时,我经常复制粘贴测试用例和描述,然后只修改其中的一部分来测试不同的边界情况。她建议我使用嵌套测试。我们尝试了一下,我立刻就爱上了这种方法。
以前我写的测试用例是这样的:

  • 账户
    • 当提取金额超过当前余额时,应抛出异常。
    • 余额应减少提取金额。

你可以做类似的事情。

  • 账户
    • 退出
      • 当金额大于当前余额时,应抛出异常。
      • 应将余额减少该金额

使用 JUnit 5 时,它看起来像这样:

    @DisplayName("An account")
    public class AccountTest {

        @Nested
        @DisplayName("withdrawal")
        class Withdrawal {

            @Test
            @DisplayName("should throw an exception when the amount greater that the current balance")
            public void failureBalanceExceeded() {
                // do some tests here
            }

            @Test
            @DisplayName("should reduce the balance by the amount")
            public void success() {
                // do some tests here
            }
        }
    }
Enter fullscreen mode Exit fullscreen mode

同样,由于需要将测试包装在嵌套类中,因此代码行数会增加,@Nested但这会使测试本身更加简洁。

扩展

@ExtendWithJUnit 5 的设计理念是高度可扩展。可以通过在类级别使用注解来添加自定义或第三方扩展。

Spring Boot

例如,Spring Boot 集成测试现在可以通过以下方式运行@ExtendWith(SpringExtension.class)。请注意,这仅适用于 Spring Boot 2.x 及更高版本。

Mockito 扩展

将会有一个更新版本MockitoExtension,可以实现类似的功能:

    @ExtendWith(MockitoExtension.class)
    class MyMockitoTest {

        @BeforeEach
        void init(@Mock Person person) {
            when(person.getName()).thenReturn("Dilbert");
        }

        @Test
        void simpleTestWithInjectedMock(@Mock Person person) {
            assertEquals("Dilbert", person.getName());
        }
    }
Enter fullscreen mode Exit fullscreen mode

所以你既不需要编写Person person = mock(Person.class)也不需要使用@Mock private Person person

从4到5的迁移

JUnit 5 的这些新特性是有代价的:它们与 JUnit 4 测试不兼容。这被称为 JUnit Jupiter。

“等等,那我现有的 500 个测试用例怎么办?”你可能会问。其实情况并没有你想的那么糟糕。JUnit 团队做了一件很聪明的事,他们把所有 JUnit Jupiter 的代码和注解都移到了一个单独的包里,这样就可以在同一个代码库里同时使用 JUnit 4 和 JUnit 5 了。你仍然需要添加新的 JUnit 平台,JUnit 4 的测试用例被称为 JUnit Vintage。这里有一篇关于迁移的不错文章,你可以在这里找到。

我们有一个包含数百个测试的项目,我们正在逐步迁移它们。所有新测试都使用 JUnit 5 编写,一旦需要修改现有测试,我们就进行迁移。这基本上会删除所有 JUnit测试,并用新版本旧版本import进行替换@Before@BeforeEach@BeforeClass@BeforeAll

结论

虽然 Java 本身可以通过引入元编程(元编程也有其缺点)或至少允许使用字符串字面量作为方法名来使测试更具可读性,从而得到很大的改进,但 JUnit 5 比 JUnit 4 要好得多,而且我认为将来会有很多扩展功能推出。

此外,JUnit 的断言库也有很多改进,但由于我使用的是AssertJ,所以没有涉及这部分内容。详情请参阅 JUnit 5 文档。

文章来源:https://dev.to/stealthmusic/why-you-should-start-using-junit-5-5gk2