JUnit 5 @Nested 注释的目的是什么?

问题描述 投票:0回答:5

在 JUnit 5 中,有一个新的注释:

@Nested

我理解注释是如何工作的,我理解为什么我们使用嵌套类, 我只是不明白为什么我们需要有嵌套测试类。

java unit-testing junit nested junit5
5个回答
52
投票

我只是不明白为什么我们需要在我们的 测试。

@Nested
组织大型测试班确实很有意义。

典型用例

开发团队经常会定义一个测试类来进行测试。 这是一个共享的良好实践,但它也可能使您的测试类变得非常大并且有数百行。您确实可以使用多种测试方法来测试类,每个测试方法有多个场景,以及单元测试方法中所需的一些初始化步骤来测试场景。
所有这些自然会增加测试班的规模。
超过阈值(可能是 500 行或左右),就有理由问自己是否需要重构。

一个大类(无论是否是测试类),即使组织得很好,也比多个类将具有高内聚/关系的事物分组更难阅读和维护。
在单元测试用例中,有时情况可能更糟,因为您可能找不到测试场景并在其存在时编写新的测试场景,但由于测试类很大而无法找到它。

@Nested
:解决方案

@Nested
通过提供在主(外部)测试类的多个嵌套类中分组多个测试方法的可能性来解决此问题。
主(外部)测试类中定义的所有嵌套类的测试方法都作为任何测试方法进行处理。所以
@BeforeEach
@AfterEach
@ExtendWith
... 适用于所有这些。
唯一的例外是
@BeforeAll
@AfterAll
:

只有非静态嵌套类(即内部类)可以充当

@Nested
测试课程。嵌套可以是任意深度,那些内部的 班级被认为是测试班级家族的正式成员 但有一个例外:
@BeforeAll
@AfterAll
方法不起作用 默认。原因是Java不允许静态成员 内部类。但是,可以通过以下方式绕过此限制 用注释
@Nested
测试类
@TestInstance(Lifecycle.PER_CLASS
)(请参阅测试实例生命周期)。

@Nested
与采用 @DisplayName
 值的 
String
 结合使用会变得更加精细,因为显示名称将用于 IDE 和构建工具中的测试报告,并且可能包含空格、特殊字符,甚至表情符号。 

示例

我有一个

FooService
,有多种方法、多种场景。 我可以将相同问题的场景分组到单元测试类的嵌套类中。
在这里,我选择测试方法来对它们进行分组(所以我按场景进行分组),但如果有意义的话,鉴别器可能是另一回事。

例如:

public class FooServiceTest {

    Foo foo;

    // invoked for ALL test methods
    @BeforeEach
    public void beforeEach() {
         Foo foo = new Foo(...);
    }

    @Nested
    @DisplayName("findWith methods")
    class FindMethods {
        @Test
        void findWith_when_X() throws Exception {
             //...
             foo.findWith(...);
             //...
        }
        @Test
        void findWith_when_Y() throws Exception {
             //...
             foo.findWith(...);
             //...

        }
        @Test
        void findWith_when_Z() throws Exception {
             //...
             foo.findWith(...);
             //...
        }           
    }

    @Nested
    @DisplayName("findAll methods")
    class FindAllMethods {
        @Test
        void findAll_when_X() throws Exception {
             //...
             foo.findAll(...);
             //...
        }
        @Test
        void findAll_when_Y() throws Exception {
             //...
             foo.findAll(...);
             //...

        }
        @Test
        void findAll_when_Z() throws Exception {
             //...
             foo.findAll(...);
             //...
        }   
    }   

    @Nested
    @DisplayName("computeBar methods")
    class ComputeBarMethods {   
         //...

    }

    @Nested
    @DisplayName("saveOrUpdate methods")
    class SaveOrUpdateMethods { 
         //...

    }
}

IDE 中的示例渲染

Nesteds 的子方法默认折叠:

如果测试失败或根据需要,您可以展开嵌套的子方法:


32
投票

@Nested
注释允许您拥有一个本质上是测试类的内部类,允许您将多个测试类分组在同一父级下(具有相同的初始化)。


9
投票

我的所有测试都需要运行数据库服务器。我的大多数测试还需要数据库中有一个

Users
表,以便能够登录。除此之外,有些测试还需要
Friends
表,以便能够登录和查询好友。

每个资源都有设置和拆卸。我必须启动和停止服务器,创建和删除表。

使用

@Nested
注释,我可以将测试分组到嵌套类的层次结构中,以便每个测试都能获得层次结构上所有测试的设置和拆卸。

这种嵌套测试的想法在 Ruby 中很流行。在 Java 中,Junit 4 是由 HierarchicalContextRunner 实现的。请参阅其页面上的理由https://github.com/bechte/junit-hierarchicalcontextrunner/wiki


0
投票

@Nested - 主要从 Junit5 开始,提供我们正在尝试做的功能的延续逻辑。 将业务测试场景拆分为多个类,@nested正在使用。


0
投票

它还可以(使用解决方法)将类提取到单独的文件,但仍将它们显示为测试视图和测试报告中顶级类的子层次结构。

确保提取的类被标记为

abstract
以避免运行它们两次。请参阅https://github.com/junit-team/junit5/issues/1750

这是一个使用 Kotlin 的示例:

class MyContainerTest {
    @Nested inner class MyNestedTestsOne : MyNestedTest1()
    @Nested inner class MyNestedTestsTwo : MyNestedTest2()

    // Can also have regular unit tests
    @Test
    fun myUnitTestInContainer() { /* ... */ }
}

MyNestedTest1.kt:

abstract class MyNestedTest1 {
    @Test
    fun myUnitTestInNestedClass1() { /* ... */ }
}

MyNestedTest2.kt:

abstract class MyNestedTest2 {
    @Test
    fun myUnitTestInNestedClass2() { /* ... */ }
}
© www.soinside.com 2019 - 2024. All rights reserved.