4.25. Testing

Spring Boot提供了许多实用程序和注解,可以在测试应用程序时提供帮助。测试支持由两个模块提供:spring-boot-test包含核心项,spring-boot-test-autoconfigure支持测试的自动配置。

大多数开发人员都使用spring-boot-starter-test 启动器,该程序同时导入Spring Boot测试模块以及JUnit Jupiter,AssertJ,Hamcrest和许多其他有用的库。

启动程序还带来了老式引擎,因此您可以运行JUnit 4和JUnit 5测试。如果已将测试迁移到JUnit 5,则应排除对JUnit 4的支持,如以下示例所示:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>

4.25.1。测试范围依赖项

spring-boot-starter-test 启动器(test scope中)包含以下提供的库:

  • JUnit 5(包括用于与JUnit 4向后兼容的老式引擎:事实上的标准,用于Java应用程序的单元测试。
  • Spring Test和Spring Boot Test:对Spring Boot应用程序的实用工具和集成测试支持。
  • AssertJ:流畅的断言库。
  • Hamcrest:匹配对象库(也是约束或谓词)。
  • Mockito:一个Java 模拟框架。
  • JSONassert:JSON的断言库。
  • JsonPath:JSON的XPath。

通常,我们发现这些通用库在编写测试时很有用。如果这些库不满足您的需求,则可以添加自己的其他测试依赖项。

4.25.2。测试Spring应用程序

依赖注入的主要优点之一是,它应该使您的代码更易于进行单元测试。您可以使用new运算符实例化对象,而无需使用Spring。您还可以使用模拟对象而不是实际的依赖项。

通常,您需要超越单元测试并开始集成测试(使用Spring ApplicationContext)。能够进行集成测试而无需部署应用程序或连接到其他基础结构是很有用的。

Spring框架包括用于此类集成测试的专用测试模块。您可以直接向其声明org.springframework:spring-test依赖项,也可以使用spring-boot-starter-test“启动器”将其引入。

如果您以前没有使用过spring-test模块,则应先阅读Spring Framework参考文档的相关部分

4.25.3。测试Spring Boot应用程序

Spring Boot应用程序是Spring ApplicationContext,因此除了对普通Spring上下文进行正常测试以外,无需执行任何其他特殊操作即可对其进行测试。

默认情况下,Spring Boot的外部属性,日志记录和其他功能仅在用于SpringApplication创建时才安装在上下文中。

Spring Boot提供了一个@SpringBootTest注释,当您需要Spring Boot功能时,它可以用作标准注释spring-test @ContextConfiguration的替代。注释通过SpringApplication创建在测试中使用过的ApplicationContext来起作用。除了@SpringBootTest,还提供许多其他注释,用于测试应用程序的更多特定部分。

如果使用的是JUnit 4,请不要忘记也将@RunWith(SpringRunner.class)添加到测试中,否则注释将被忽略。如果您使用的是JUnit 5,则无需添加等价项@RunWith(SpringExtension.class)@SpringBootTest和其他@…Test注释已经在其中进行了注释。

默认情况下,@SpringBootTest不会启动服务器。您可以使用@SpringBootTest的webEnvironment属性进一步优化测试的运行方式:

  • MOCK(默认):加载Web ApplicationContext并提供模拟Web环境。使用此注释时,不会启动嵌入式服务器。如果您的类路径中没有网络环境,则此模式将透明地退回到创建常规非网络ApplicationContext。它可以与Web应用程序结合使用@AutoConfigureMockMvc@AutoConfigureWebTestClient用于基于模拟的测试。
  • RANDOM_PORT:加载WebServerApplicationContext并提供真实的网络环境。嵌入式服务器将启动并在随机端口上侦听。
  • DEFINED_PORT:加载WebServerApplicationContext并提供真实的网络环境。嵌入式服务器将启动并在已定义的端口(来自application.properties)上或在的默认8080端口上进行侦听。
  • NONE:通过使用SpringApplication加载ApplicationContext,但不提供任何网络环境(模拟或其他方式)。

如果您的测试是@Transactional,则默认情况下它将在每个测试方法的末尾回滚事务。但是,由于将这种安排与一个RANDOM_PORT或多个DEFINED_PORT隐式提供真实的servlet环境一起使用,HTTP客户端和服务器在单独的线程中运行,因此在单独的事务中运行。在这种情况下,服务器上启动的任何事务都不会回滚。

如果您的应用程序对管理服务器使用其他端口,则webEnvironment = WebEnvironment.RANDOM_PORT@SpringBootTest也将在单独的随机端口上启动管理服务器。

检测Web应用程序类型

如果Spring MVC可用,则配置基于常规MVC的应用程序上下文。如果您只有Spring WebFlux,我们将检测到它并配置基于WebFlux的应用程序上下文。

如果两者都存在,则Spring MVC优先。如果要在这种情况下测试反应式Web应用程序,则必须设置spring.main.web-application-type属性:

@SpringBootTest(properties = "spring.main.web-application-type=reactive")
class MyWebFluxTests { ... }

检测测试配置

如果您熟悉Spring Test Framework,则可能习惯于使用@ContextConfiguration(classes=...)来指定要加载哪个Spring @Configuration。另外,您可能经常在测试中使用@Configuration嵌套类。

在测试Spring Boot应用程序时,通常不需要这样做。只要您没有明确定义,Spring Boot的 @*Test注释就会自动搜索您的主要配置。

搜索算法从包含测试的程序包开始工作,直到找到带有@SpringBootApplication@SpringBootConfiguration注释的类。只要您以合理的方式对代码进行结构化,通常就可以找到您的主要配置。

如果使用测试注释来测试应用程序的更特定的部分,则应避免在main方法的应用程序类上添加特定于特定区域的配置设置。

@SpringBootApplication的基础组件扫描配置定义排除了用于确保切片按预期工作的过滤器。如果在@SpringBootApplication注解类上使用显式指令@ComponentScan,请注意这些过滤器将被禁用。如果使用切片,则应再次定义它们。

如果要自定义主要配置,则可以使用嵌套@TestConfiguration类。与将使用嵌套类代替应用程序的主要配置的@Configuration嵌套类不同,除了应用程序的主要配置之外,还使用了@TestConfiguration嵌套类。

Spring的测试框架在测试之间缓存应用程序上下文。因此,只要您的测试共享相同的配置(无论如何发现),加载上下文的潜在耗时过程就只会发生一次。

排除测试配置

如果您的应用程序使用组件扫描(例如,如果使用@SpringBootApplication或@ComponentScan),您可能会发现仅为特定测试创建的顶级配置类到处意外使用。

如我们先前所见,可以在测试的内部类上使用@TestConfiguration来自定义主要配置。当放置在顶级类上时,@TestConfiguration指示不应通过扫描来拾取src/test/java中的类。然后,可以在需要的位置显式导入该类,如以下示例所示:

@SpringBootTest
@Import(MyTestsConfiguration.class)
class MyTests { @Test
void exampleTest() {
...
} }

如果您直接使用@ComponentScan(即不是通过@SpringBootApplication),则需要向其注册TypeExcludeFilter

使用应用程序参数

如果您的应用程序需要参数,则可以使用args属性将其注入@SpringBootTest

@SpringBootTest(args = "--app.test=one")
class ApplicationArgumentsExampleTests { @Test
void applicationArgumentsPopulated(@Autowired ApplicationArguments args) {
assertThat(args.getOptionNames()).containsOnly("app.test");
assertThat(args.getOptionValues("app.test")).containsOnly("one");
} }

在模拟环境中进行测试

默认情况下,@SpringBootTest不启动服务器。如果您有要在此模拟环境下进行测试的Web点,则可以另外配置MockMvc,如以下示例所示:

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @SpringBootTest
@AutoConfigureMockMvc
class MockMvcExampleTests { @Test
void exampleTest(@Autowired MockMvc mvc) throws Exception {
mvc.perform(get("/")).andExpect(status().isOk()).andExpect(content().string("Hello World"));
} }

如果您只想专注于Web层而不希望完全完成ApplicationContext,请考虑使用@WebMvcTest代替。

或者,您可以配置WebTestClient,如以下示例所示:

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.reactive.server.WebTestClient; @SpringBootTest
@AutoConfigureWebTestClient
class MockWebTestClientExampleTests { @Test
void exampleTest(@Autowired WebTestClient webClient) {
webClient.get().uri("/").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo("Hello World");
} }

在模拟环境中进行测试通常比在完整的Servlet容器中运行更快。但是,由于模拟发生在Spring MVC层,因此无法使用MockMvc直接测试依赖于较低级别Servlet容器行为的代码。

例如,Spring Boot的错误处理基于Servlet容器提供的“错误页面”支持。这意味着,尽管您可以按预期测试MVC层引发并处理异常,但是您无法直接测试是否呈现了特定的自定义错误页面。如果需要测试这些较低级别的问题,则可以按照下一节中的描述启动一个完全运行的服务器。

使用正在运行的服务器进行测试

如果需要启动完全运行的服务器,建议您使用随机端口。如果使用@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT),则每次运行测试时都会随机选择一个可用端口。

@LocalServerPort注释可用于注入使用的实际端口到您的测试。为了方便起见,需要对启动的服务器进行REST调用的测试可以另外使用@Autowire WebTestClient,它解析到正在运行的服务器的相对链接,并带有用于验证响应的专用API,如以下示例所示:

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.web.reactive.server.WebTestClient; @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class RandomPortWebTestClientExampleTests { @Test
void exampleTest(@Autowired WebTestClient webClient) {
webClient.get().uri("/").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo("Hello World");
} }

此设置要求spring-webflux在类路径上。如果您不能或不会添加webflux,Spring Boot还提供了以下TestRestTemplate功能:

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate; import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class RandomPortTestRestTemplateExampleTests { @Test
void exampleTest(@Autowired TestRestTemplate restTemplate) {
String body = restTemplate.getForObject("/", String.class);
assertThat(body).isEqualTo("Hello World");
} }

自定义WebTestClient

要自定义WebTestClient Bean,请配置WebTestClientBuilderCustomizer Bean。被WebTestClient.Builder调用的任何这样的bean用于创建WebTestClient。

使用JMX

由于测试上下文框架缓存上下文,因此默认情况下禁用JMX以防止相同组件在同一域上注册。如果此类测试需要访问MBeanServer,请考虑将其标记为dirty

@ExtendWith(SpringExtension.class)
@SpringBootTest(properties = "spring.jmx.enabled=true")
@DirtiesContext
class SampleJmxTests { @Autowired
private MBeanServer mBeanServer; @Test
void exampleTest() {
// ...
} }

模拟和间谍Beans

运行测试时,有时有必要在应用程序上下文中模拟某些组件。例如,您可能在开发过程中无法使用某些远程服务的facade。当您要模拟在实际环境中可能难以触发的故障时,模拟也很有用。

Spring Boot包含一个@MockBean注释,可用于为您的ApplicationContext中的定义bean 的Mockito模拟。您可以使用注解添加新bean或替换单个现有bean定义。注释可以直接用于测试类,测试中的字段或@Configuration类和字段。在字段上使用时,还将注入创建的模拟的实例。每种测试方法后,模拟bean 都会自动重置。

如果您的测试使用Spring Boot的测试注释之一(例如@SpringBootTest),则此功能会自动启用。要以其他方式使用此功能,必须显式添加侦听器,如以下示例所示:

@TestExecutionListeners(MockitoTestExecutionListener.class)

下面的示例用RemoteService模拟实现替换现有的bean:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.*;
import org.springframework.boot.test.context.*;
import org.springframework.boot.test.mock.mockito.*; import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*; @SpringBootTest
class MyTests { @MockBean
private RemoteService remoteService; @Autowired
private Reverser reverser; @Test
void exampleTest() {
// RemoteService has been injected into the reverser bean
given(this.remoteService.someCall()).willReturn("mock");
String reverse = reverser.reverseSomeCall();
assertThat(reverse).isEqualTo("kcom");
} }

@MockBean不能用于模拟应用程序上下文刷新期间执行的bean的行为。到执行测试时,应用程序上下文刷新已完成,并且配置模拟行为为时已晚。我们建议在这种情况下使用一种方法来创建和配置模拟@Bean。

另外,您可以使用@SpyBean来包装任何现有的Mockito spy的bean 。

Spring的测试框架在测试之间缓存应用程序上下文,并为共享相同配置的测试重用上下文,但是@MockBean@SpyBean的使用影响缓存密钥,这很可能会增加上下文的数量。

如果您使用@SpyBean通过@Cacheable方法监视一个bean,则必须使用-parameters编译应用程序。这样可以确保一旦侦察到bean,参数名称就可用于缓存基础结构。

自动配置的测试

Spring Boot的自动配置系统适用于应用程序,但有时对于测试来说可能有点过多。它通常仅有助于加载测试应用程序“切片”所需的配置部分。例如,您可能想要测试Spring MVC控制器是否正确映射了URL,并且您不想在这些测试中涉及数据库调用,或者您想要测试JPA实体,并且对那些JPA实体不感兴趣,并且你在测试运行时对网络层不感兴趣。

spring-boot-test-autoconfigure模块包括许多注释,可用于自动配置此类“切片”。它们中的每一个都以类似的方式工作,提供了一个@...Test注释加载ApplicationContext以及一个或多个@AutoConfigure...,可用于自定义自动配置设置的注释。

每个切片将组件扫描限制为适当的组件,并加载一组非常受限制的自动配置类。如果您需要排除其中之一,则大多数@...Test注释都提供一个excludeAutoConfiguration属性。或者,您可以使用@ImportAutoConfiguration#exclude

@...Test不支持在一个测试中 通过使用多个注释来包含多个“切片” 。如果需要多个“切片”,请选择其中一个@...Test注释,并手动添加其他“切片” 的@AutoConfigure...注释。

也可以将@AutoConfigure...注释与标准@SpringBootTest注释一起使用。如果您对“切片”应用程序不感兴趣,但需要一些自动配置的测试bean,则可以使用此组合。

Auto-configured JSON Tests

Auto-configured Spring MVC Tests

Auto-configured Spring WebFlux Tests

Auto-configured Data JPA Tests

Auto-configured JDBC Tests

Auto-configured Data JDBC Tests

Auto-configured jOOQ Tests

Auto-configured Data MongoDB Tests

Auto-configured Data Neo4j Tests

Auto-configured Data Redis Tests

Auto-configured Data LDAP Tests

Auto-configured REST Clients

Auto-configured Spring REST Docs Tests

Additional Auto-configuration and Slicing

User Configuration and Slicing

Using Spock to Test Spring Boot Applications

4.25.4. Test Utilities

跳过

20191127 Spring Boot官方文档学习(4.25)的更多相关文章

  1. 20191127 Spring Boot官方文档学习(9.1-9.3)

    9."使用方法"指南 9.1.Spring Boot应用程序 9.1.1.创建自己的FailureAnalyzer FailureAnalyzer被包装在FailureAnalys ...

  2. 20191127 Spring Boot官方文档学习(4.10)

    4.10.使用SQL数据库 从使用JdbcTemplate直接的JDBC访问到完整的"对象关系映射"技术(例如Hibernate),Spring框架为使用SQL数据库提供了广泛的支 ...

  3. 20191127 Spring Boot官方文档学习(4.11)

    4.11.使用NoSQL技术 Spring Data提供了其他项目来帮助您访问各种NoSQL技术,包括: Redis MongoDB Neo4J Solr Elasticsearch Cassandr ...

  4. 20191127 Spring Boot官方文档学习(4.12)

    4.12.缓存(Caching) Spring框架提供了对应用程序透明添加缓存的支持.从本质上讲,抽象将缓存应用于方法,从而根据缓存中可用的信息减少执行次数.缓存逻辑是透明应用的,不会对调用者造成任何 ...

  5. 20191127 Spring Boot官方文档学习(4.13)

    4.13.Messaging Spring框架为与消息传递系统集成提供了广泛的支持,从使用JmsTemplate简化JMS API到完整的异步接收消息的基础结构.Spring AMQP为高级消息队列协 ...

  6. 20191127 Spring Boot官方文档学习(4.14-4.17)

    4.14.使用RestTemplate调用REST服务 如果需要从应用程序调用远程REST服务,则可以使用Spring Framework的RestTemplate类.由于RestTemplate实例 ...

  7. 20191127 Spring Boot官方文档学习(4.18-4.24)

    4.18.JTA的分布式事务 通过使用Atomikos或Bitronix嵌入式事务管理器,Spring Boot支持跨多个XA资源的分布式JTA事务.部署到合适的Java EE应用程序服务器时,还支持 ...

  8. 20191127 Spring Boot官方文档学习(5)

    5.Spring Boot Actuator:可投入生产的功能 Spring Boot包含许多其他功能,可帮助您在将应用程序投入生产时监控和管理您的应用程序.您可以选择使用HTTP端点或JMX管理和监 ...

  9. 20191127 Spring Boot官方文档学习(6-8)

    6.部署Spring Boot应用程序 在部署应用程序时,Spring Boot的灵活打包选项提供了很多选择.您可以将Spring Boot应用程序部署到各种云平台,容器映像(例如Docker)或虚拟 ...

随机推荐

  1. python中字符串格式化的两种方法

    知识点汇总;1-字符串格式化输出方法一: % 1-print('名字是 %s,年龄是%s' % (name ,age)) 2- %s ---字符串-----相当于执行了str() 3- (name , ...

  2. 跨平台开发框架DevExtreme v19.1.4正式发布|附下载

    DevExtreme Complete Subscription是性能最优的 HTML5,CSS 和 JavaScript 移动.Web开发框架,可以直接在Visual Studio集成开发环境,构建 ...

  3. gdb命令小结

    GDB命令小结 gdb <filename> : 调试指定程序文件 r : run 的简写,运行被调试程序, 如果此前没有下过断点,则执行完整个程序:如果有断点, 则程序暂停在第一个可用断 ...

  4. HDU-4185-Oil Skimming(最大匹配)

    链接: https://vjudge.net/problem/HDU-4185 题意: Thanks to a certain "green" resources company, ...

  5. Java word 内容读取

    1.添加依赖关系(网上好多帖子没有写依赖,害我找半天) <dependency>            <groupId>org.apache.poi</groupId& ...

  6. 17. ClustrixDB 日志管理

    ClustrixDB记录关于重要和有问题的查询的详细信息.这些日志有助于确定以下事项: 慢速查询 资源争用 SQL错误 读取意外数量行的查询 模式变化 全局变量的修改 集群的改变 默认情况下,查询日志 ...

  7. toJSON() 方法,将 Date 对象转换为字符串,并格式化为 JSON 数据格式。

    JavaScript toJSON() 方法 定义和用法 toJSON() 方法可以将 Date 对象转换为字符串,并格式化为 JSON 数据格式. JSON 数据用同样的格式就像x ISO-8601 ...

  8. [luogu]P1070 道路游戏[DP]

    [luogu]P1070 道路游戏 题目描述小新正在玩一个简单的电脑游戏.游戏中有一条环形马路,马路上有 n 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针 ...

  9. (77)一文了解Redis

    为什么我们做分布式使用Redis? 绝大部分写业务的程序员,在实际开发中使用 Redis 的时候,只会 Set Value 和 Get Value 两个操作,对 Redis 整体缺乏一个认知.这里对  ...

  10. Oracle-RAC sysdate和current_date时间不一致,导致客户端连接时间延迟

    [oracle@oracle-db1 ~]$ dateTue Oct 10 14:20:56 CST 2017[oracle@oracle-db1 ~]$ cat /etc/sysconfig/clo ...