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

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

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

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

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

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

使用@Nested注释,我可以在嵌套类的层次结构中对测试进行分组,以便每个测试都能获得层次结构中所有测试的设置和拆除。

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

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

@Nested使组织大型测试类非常有意义。

典型用例

对于在要测试的类和与之关联的测试类(这是一个共享的良好实践)之间保持1对1映射的开发人员团队,其中包含一些数百行的大型测试类是不必要的坏模式。
您确实可以使用多个方法来测试类,每个方法都有多个方案,还有unit testing方法中需要的一些初始化步骤来测试方案。
所有这些都会自然地增加测试类的大小。
当超过阈值(可能是500或大约)时,问自己是否需要重构是合理的。

一个大型课程(测试课程或非测试课程)组织得更好,比多个测试课程更难以阅读和维护,这些测试课程之间具有高凝聚力/关系。
在unit testing案例中,它可能仍然更加烦人,因为您可能找不到测试场景并在它存在时编写新场景,但您无法在大型测试类中找到它。

@Nested :解决方案

@Nested解决了这个问题,它提供了在主测试类的嵌套类中表达几组测试方法之间关系的可能性。
请注意,外部测试类中定义的所有嵌套类的测试方法都作为外部类测试方法处理( @BeforeEach@AfterEach@ExtendWith …)。
唯一的例外是@BeforeAll@AfterAll

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

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

我有一个FooService有多种方法和多种方案。 我可以在unit testing类中对相同关注的场景进行分组。
在这里,我选择测试方法对它们进行分组,但鉴别器可能是另一回事,如果它有意义的话。

例如 :

 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插件概述

如果遇到或测试失败或按需,您可以展开嵌套的子方法:

展开JUnit Eclipse插件失败