我只是不明白为什么我们需要在我们的 测试。
@Nested
组织大型测试班确实很有意义。
典型用例
开发团队经常会定义一个测试类来进行测试。
这是一个共享的良好实践,但它也可能使您的测试类变得非常大并且有数百行。您确实可以使用多种测试方法来测试类,每个测试方法有多个场景,以及单元测试方法中所需的一些初始化步骤来测试场景。
所有这些自然会增加测试班的规模。
超过阈值(可能是 500 行或左右),就有理由问自己是否需要重构。
一个大类(无论是否是测试类),即使组织得很好,也比多个类将具有高内聚/关系的事物分组更难阅读和维护。
在单元测试用例中,有时情况可能更糟,因为您可能找不到测试场景并在其存在时编写新的测试场景,但由于测试类很大而无法找到它。
@Nested
:解决方案
@Nested
通过提供在主(外部)测试类的多个嵌套类中分组多个测试方法的可能性来解决此问题。@BeforeEach
、@AfterEach
、@ExtendWith
... 适用于所有这些。@BeforeAll
和 @AfterAll
:
只有非静态嵌套类(即内部类)可以充当
测试课程。嵌套可以是任意深度,那些内部的 班级被认为是测试班级家族的正式成员 但有一个例外:@Nested
和@BeforeAll
方法不起作用 默认。原因是Java不允许静态成员 内部类。但是,可以通过以下方式绕过此限制 用注释@AfterAll
测试类@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 的子方法默认折叠:
如果测试失败或根据需要,您可以展开嵌套的子方法:
@Nested
注释允许您拥有一个本质上是测试类的内部类,允许您将多个测试类分组在同一父级下(具有相同的初始化)。
我的所有测试都需要运行数据库服务器。我的大多数测试还需要数据库中有一个
Users
表,以便能够登录。除此之外,有些测试还需要 Friends
表,以便能够登录和查询好友。
每个资源都有设置和拆卸。我必须启动和停止服务器,创建和删除表。
使用
@Nested
注释,我可以将测试分组到嵌套类的层次结构中,以便每个测试都能获得层次结构上所有测试的设置和拆卸。
这种嵌套测试的想法在 Ruby 中很流行。在 Java 中,Junit 4 是由 HierarchicalContextRunner 实现的。请参阅其页面上的理由https://github.com/bechte/junit-hierarchicalcontextrunner/wiki。
@Nested - 主要从 Junit5 开始,提供我们正在尝试做的功能的延续逻辑。 将业务测试场景拆分为多个类,@nested正在使用。
它还可以(使用解决方法)将类提取到单独的文件,但仍将它们显示为测试视图和测试报告中顶级类的子层次结构。
确保提取的类被标记为
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() { /* ... */ }
}