在单体 SpringBoot 应用程序中创建集成测试
Creating integration tests in a monolithic SpringBoot application
我被要求为一个非常大的 SpringBoot 项目中的服务创建一个集成测试,该项目产生了数十个已实现的服务。当应用程序执行时,所有这些服务都会被部署——我想避免部署与我为其创建测试的服务无关的所有服务。不幸的是,我(还)没有像我希望的那样有足够的 spring 启动测试经验,因此我想知道解决这个问题的最佳方法是什么。
我正在考虑在测试 class 中用 @MockBean
注释对所有不相关的服务进行注释,并在测试 class 中对所有相关的服务进行注释 @Autowire
,但我不确定这是否合适路要走。谁能指出我正确的方向?
谢谢。
如果您必须创建 spring 集成测试,您必须:
- 通过在测试 class 上使用注释来调用 spring 上下文 - 例如:@RunWith(SpringJUnit4ClassRunner.class)
- 在您不打算测试但它们是测试的一部分的服务上使用@MockBean 或@SpyBean 注释 methods/class
- 在您要测试的 class 上使用 @Autowired 注释。
要验证结果,您可以使用 Junit4 或 Junit5 断言,为了验证行为,您可以使用 Mockito
答案在很大程度上取决于集成测试的范围。我将尝试涵盖两种主要方式,您可以 google 等待更多示例和详细信息。 Spring Boot testing documentation也是你的朋友
切片
Spring Boot 提供名为 slices. For example there's a slice for testing your controllers - @WebMvcTest
的测试实用程序 - 此测试将加载所有配置,以便从 HTTP 和指定的控制器 (@WebMvcTest(YourController.class)
) 调用您的应用程序。之后,您需要决定如何处理该控制器的依赖项。
您可以:
- 用
@MockBean
来嘲笑他们。
- 用
@Import
提供真正的实现(或附加配置)(然后你必须再次处理新导入的依赖项的依赖项)。
- 加载 Spring 引导自动配置的附加部分。这可以使用
@AutoConfigureSomething
注释来完成。 - 所有切片基本上都是自动配置注释的组合,您可以自由地将它们添加到您的测试中。例如,查看 annotations on DataJpaTest 以了解如何添加功能以设置 Spring 带有测试数据库的引导数据 JPA。
您的每个测试最多可以有一个切片,但您可以导入任意数量的附加服务、配置、模拟、自动配置等。关键是——您选择为您的测试配置的内容;具有新依赖关系的新不相关服务不应破坏现有测试。
SpringBootTest
另一种方法是 @SpringBootTest
注释——这是相反的方向——默认情况下它会加载所有内容,您可以使用 @MockBean
、@EnableAutoConfiguration(exclude=SomeClass)
等排除不需要的内容.
添加新服务时当然存在破坏现有测试的危险。 - 这不应该经常发生,因为一切都是自动配置的,但它仍然是可能的,尤其是在具有更多配置的整体中。
我有一个类似的问题,希望能够在 Springboot 中隔离特定组件(或服务)的集成测试;我的限制是我必须使用 JUnit5 和 Mockito。
我从 Baeldung 找到了这两个帖子,它们像往常一样只给出了特定场景的特定答案,而不是通用解决方案:
https://www.baeldung.com/injecting-mocks-in-spring
https://www.baeldung.com/junit-5-runwith
长话短说我找到了如下解决方案:
在集成测试的测试文件夹中为您的组件创建如下配置 class(下面的示例是我想要集成测试拦截器组件;我有编辑名称):
您可以模拟 bean,或者您可以实例化没有依赖关系的 bean(可以说是叶 bean)
然后在你的集成测试中你可以使用后一个配置。为了让您的组件在测试(剪切)下满足其依赖性。我的拦截器有 3 个依赖级别:
最后,在您的集成测试中,您可以使用以下方法来模拟您模拟出的 bean 的方法调用:
when(cut.getInitRequestRepo().initRequest(ArgumentMatchers.any(InParamInitRequest.class))).thenReturn(outParamInitRequest);
我使用的POM依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<!-- Testing with Mocks -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.11.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>3.11.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.7.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.10.0</version>
<scope>test</scope>
</dependency>
我被要求为一个非常大的 SpringBoot 项目中的服务创建一个集成测试,该项目产生了数十个已实现的服务。当应用程序执行时,所有这些服务都会被部署——我想避免部署与我为其创建测试的服务无关的所有服务。不幸的是,我(还)没有像我希望的那样有足够的 spring 启动测试经验,因此我想知道解决这个问题的最佳方法是什么。
我正在考虑在测试 class 中用 @MockBean
注释对所有不相关的服务进行注释,并在测试 class 中对所有相关的服务进行注释 @Autowire
,但我不确定这是否合适路要走。谁能指出我正确的方向?
谢谢。
如果您必须创建 spring 集成测试,您必须: - 通过在测试 class 上使用注释来调用 spring 上下文 - 例如:@RunWith(SpringJUnit4ClassRunner.class) - 在您不打算测试但它们是测试的一部分的服务上使用@MockBean 或@SpyBean 注释 methods/class - 在您要测试的 class 上使用 @Autowired 注释。 要验证结果,您可以使用 Junit4 或 Junit5 断言,为了验证行为,您可以使用 Mockito
答案在很大程度上取决于集成测试的范围。我将尝试涵盖两种主要方式,您可以 google 等待更多示例和详细信息。 Spring Boot testing documentation也是你的朋友
切片
Spring Boot 提供名为 slices. For example there's a slice for testing your controllers - @WebMvcTest
的测试实用程序 - 此测试将加载所有配置,以便从 HTTP 和指定的控制器 (@WebMvcTest(YourController.class)
) 调用您的应用程序。之后,您需要决定如何处理该控制器的依赖项。
您可以:
- 用
@MockBean
来嘲笑他们。 - 用
@Import
提供真正的实现(或附加配置)(然后你必须再次处理新导入的依赖项的依赖项)。 - 加载 Spring 引导自动配置的附加部分。这可以使用
@AutoConfigureSomething
注释来完成。 - 所有切片基本上都是自动配置注释的组合,您可以自由地将它们添加到您的测试中。例如,查看 annotations on DataJpaTest 以了解如何添加功能以设置 Spring 带有测试数据库的引导数据 JPA。
您的每个测试最多可以有一个切片,但您可以导入任意数量的附加服务、配置、模拟、自动配置等。关键是——您选择为您的测试配置的内容;具有新依赖关系的新不相关服务不应破坏现有测试。
SpringBootTest
另一种方法是 @SpringBootTest
注释——这是相反的方向——默认情况下它会加载所有内容,您可以使用 @MockBean
、@EnableAutoConfiguration(exclude=SomeClass)
等排除不需要的内容.
添加新服务时当然存在破坏现有测试的危险。 - 这不应该经常发生,因为一切都是自动配置的,但它仍然是可能的,尤其是在具有更多配置的整体中。
我有一个类似的问题,希望能够在 Springboot 中隔离特定组件(或服务)的集成测试;我的限制是我必须使用 JUnit5 和 Mockito。
我从 Baeldung 找到了这两个帖子,它们像往常一样只给出了特定场景的特定答案,而不是通用解决方案: https://www.baeldung.com/injecting-mocks-in-spring https://www.baeldung.com/junit-5-runwith
长话短说我找到了如下解决方案:
在集成测试的测试文件夹中为您的组件创建如下配置 class(下面的示例是我想要集成测试拦截器组件;我有编辑名称):
您可以模拟 bean,或者您可以实例化没有依赖关系的 bean(可以说是叶 bean)
然后在你的集成测试中你可以使用后一个配置。为了让您的组件在测试(剪切)下满足其依赖性。我的拦截器有 3 个依赖级别:
最后,在您的集成测试中,您可以使用以下方法来模拟您模拟出的 bean 的方法调用:
when(cut.getInitRequestRepo().initRequest(ArgumentMatchers.any(InParamInitRequest.class))).thenReturn(outParamInitRequest);
我使用的POM依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<!-- Testing with Mocks -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.11.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>3.11.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.7.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.10.0</version>
<scope>test</scope>
</dependency>