40

在 JUnit 5 中,有一个新的注解:@Nested.

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

4

4 回答 4

32

我只是不明白为什么我们需要在测试中嵌套测试类。

@Nested组织大型测试课程非常有意义。

典型用例

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

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

@Nested: 解决方案

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

只有非静态嵌套类(即内部类)可以作为 @Nested测试类。嵌套可以任意深,并且那些内部类被认为是测试类家族的完整成员,但有一个例外:默认情况@BeforeAll@AfterAll方法不起作用。原因是 Java 不允许内部类中的静态成员。@Nested但是,可以通过使用 ) 注释测试类 来规避此限制@TestInstance(Lifecycle.PER_CLASS(请参阅测试实例生命周期)。

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

例子

我有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 中的示例渲染

嵌套的子方法默认折叠:

JUnit Eclipse 插件概述

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

在 JUnit Eclipse 插件中出现故障时展开

于 2018-08-12T14:35:22.397 回答
25

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

于 2016-03-25T13:36:13.463 回答
8

我所有的测试都需要运行一个数据库服务器。我的大多数测试还需要数据库中的Users表才能登录。除此之外,一些测试需要Friends表才能登录和查询朋友。

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

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

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

于 2016-07-14T10:06:48.017 回答
0

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

于 2020-06-24T08:46:56.433 回答