如下内容,翻译自官方文档,并结合了学习过程的demo。html
Spring Boot提供了许多实用程序和注解,帮助测试应用程序。测试支持由两个模块提供:spring-boot-test
包含核心项,spring-boot-test-autoconfigure
支持测试的自动配置。大多数开发人员使用
spring-boot-starter-test
,它同时导入 SpringBoot 测试模块以及JUnit Jupiter、AssertJ、Hamcrest和许多其余有用的库。java
此文使用当前最新稳定版本: SpringBoot 2.2.2.RELEASE
此 starter 还带来了 vintage 引擎,所以能够同时运行JUnit 4和JUnit 5测试。若是已经将测试迁移到JUnit5,那么应该排除JUnit4支持,以下例所示:react
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <exclusions> <exclusion> <!-- 此模块兼容junit4 和 junit 5,此示例直接使用 junit5 --> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> <scope>test</scope> </dependency>
spring-boot-starter-test
(依赖 scope
为 test
)包含如下库:git
依赖注入的一个主要优势是它应该使代码更容易进行单元测试。可使用新的操做符实例化对象,甚至不涉及Spring。也可使用模拟对象而不是实际依赖项。一般,您须要超越单元测试,开始集成测试(使用Spring ApplicationContext)。可以在不须要部署应用程序或链接到其余基础结构的状况下执行集成测试是很是有用的。github
Spring框架包含了一个专门的集成测试模块。能够直接向
org.springframework:spring
测试声明一个依赖项,或者使用spring-boot-starter-test
。web若是之前没有使用过
spring-test
模块,那么应该从阅读spring框架参考文档的相关部分开始。redis
SpringBoot 应用程序是 Spring ApplicationContext
,所以除了使用普通的Spring上下文以外,没必要作任何特别的事情来测试它。算法
默认状况下,只有在使用 SpringApplication
建立 Spring Boot时,它的外部属性、日志记录和其余特性才会安装在上下文中。spring
SpringBoot 提供了一个 @SpringBootTest
注解,当须要SpringBoot 特性时,它能够做为标准 spring-test
@ContextConfiguration
注解的替代。注解的工做方式是经过 SpringApplication
建立测试中使用的ApplicationContext。除了 @SpringBootTest
以外,还提供了一些其余注解,用于测试应用程序的更具体的部分。数据库
若是使用的是JUnit4,不要忘记将 @RunWith(SpringRunner.class)
添加到测试中,不然注解将被忽略。若是使用的是JUnit5,则不须要添加与 @SpringBootTest
和 其余已经使用的注解等效的 @ExtendWith(SpringExtension.class)
默认状况下,@SpringBootTest
不会启动服务器。可使用 @SpringBootTest
的 webEnvironment
属性进一步优化测试的运行方式:
MOCK
(默认):加载 web ApplicationContext
并提供模拟web环境。使用此注解时,嵌入式服务器未启动。若是类路径上没有可用的web环境,则此模式会透明地回退到建立常规的非web ApplicationContext
。它能够与 @AutoConfigureMockMvc
或 @AutoConfigureWebTestClient
结合使用,对web应用程序进行基于模拟的测试。RANDOM_PORT
:加载 WebServerApplicationContext
并提供真正的web环境。嵌入式服务器启动并在随机端口上监听。DEFINED_PORT
:加载 WebServerApplicationContext
并提供真正的web环境。嵌入式服务器将启动并在定义的端口(从 application.properties
)或默认端口8080上监听。NONE
:使用 SpringApplication
加载 ApplicationContext
,但不提供任何web环境(mock或其余)。若是测试是 @Transactional
,那么默认状况下,它会在每一个测试方法结束时回滚事务。然而,因为对随机端口或定义的端口使用这种安排隐式地提供了一个真正的servlet环境,HTTP客户机和服务器在单独的线程中运行,所以在单独的事务中运行。在这种状况下,服务器上启动的任何事务都不会回滚。
@使用 webEnvironment=webEnvironment.RANDOM_PORT
的 @SpringBootTest
也将在单独的随机端口上启动管理服务器,若是应用程序对管理服务器使用不一样的端口。
若是 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 测试框架中,可使用 @ContextConfiguration(classes=…)
来指定加载那个 Spring @Configuration
。
在测试 Spring Boot 应用程序时,这一般不是必需的。Spring Boot的 @Test 类注解在没有显式定义主配置时自动搜索主配置。
搜索算法从包含测试的包开始工做,直到找到用 @SpringBootApplication
或 @SpringBootConfiguration
注解的类为止。只要以合理的方式构造代码,一般都会找到主配置。
若是要自定义主配置,可使用嵌套的 @TestConfiguration
类。与嵌套的 @Configuration
类(将用于替代应用程序的主配置)不一样,嵌套的 @TestConfiguration
类是在应用程序的主配置额外使用的。
Spring的测试框架在测试之间缓存应用程序上下文。所以,只要您的测试共享相同的配置(不管如何发现),加载上下文的潜在耗时过程只发生一次。
若是使用了@SpringBootApplication
或@ComponentScan
扫描,针对特定测试的顶级配置类可能在任何地方都可以被获取到。
如前所述,@TestConfiguration
可用于测试的内部类,以自定义主要配置。当放置在顶级类上时,@TestConfiguration
表示 src/test/java
中的类不该该经过扫描来获取。而后,能够在须要时显式导入该类,以下例所示:
@SpringBootTest @Import(MyTestsConfiguration.class) class MyTests { @Test void exampleTest() { //... } }
若是应用程序须要参数,可使用 @SpringBootTest
的 args
属性注入它们。
@SpringBootTest(args = "--app.name=test", webEnvironment = WebEnvironment.NONE) public class ArgTests { @Test public void applicationArgsTest(@Autowired ApplicationArguments args) { assertThat(args.getOptionNames()).containsOnly("app.name"); assertThat(args.getOptionValues("app.name")).containsOnly("test"); } }
默认状况下,@SpringBootTest
不会启动服务器。若是在此模拟环境中有要测试的web端点,则能够另外配置MockMvc,以下例所示:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
public interface ConstantUtil { String body = "Hello World!"; }
@RestController public class HelloWorldController { @RequestMapping public String helloWorld(){ return ConstantUtil.body; } }
@SpringBootTest @AutoConfigureMockMvc public class MockMvcTests { @Test public void test(@Autowired MockMvc mvc) throws Exception { mvc.perform(get("/")).andExpect(status().isOk()).andExpect(content().string(ConstantUtil.body)); } }
若是您只想关注web层而不想启动一个完整的ApplicationContext
,能够考虑改用@WebMvcTest
。
另外,能够配置 WebTestClient
,以下:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency>
/** * WebTestClient<br> * WebTestClient 属于 reactive,设置spring.main.web-application-type=reactive */ @SpringBootTest(properties = "spring.main.web-application-type=reactive") @AutoConfigureWebTestClient public class MockWebTestClientTests { @Test public void test(@Autowired WebTestClient webTestClient) { webTestClient .get() .uri("/") .exchange() .expectStatus() .isOk() .expectBody(String.class) .isEqualTo(ConstantUtil.body); } }
在模拟环境中进行测试一般比使用完整的Servlet容器运行要快。可是,因为模拟发生在Spring MVC层,依赖于低级Servlet容器行为的代码不能直接用MockMvc测试。
例如,Spring Boot的错误处理基于Servlet容器提供的“错误页”支持。这意味着,虽然能够按预期测试MVC层抛出和处理异常,但不能直接测试是否呈现了特定的自定义错误页。若是须要测试这些较低级别的关注点,能够按照下一节中的说明启动彻底运行的服务器。
若是须要启动彻底运行的服务器,建议使用随机端口。若是使用 @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
,则每次运行测试时都会随机选择一个可用端口。
@LocalServerPort
注解可用于将实际使用的端口注入测试。为了方便起见,须要对启动的服务器进行REST调用的测试还能够 @Autowire
一个 WebTestClient
,它解析到正在运行的服务器的相关连接,并附带用于验证响应的专用API,以下例所示:
/** * 使用运行中的server<br> * 使用 webflux * * @author YiFeiXi */ @SpringBootTest( webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.main.web-application-type=reactive") public class RandomPortWebTestClientTests { @Test public void test(@Autowired WebTestClient webTestClient) { webTestClient .get() .uri("/") .exchange() .expectStatus() .isOk() .expectBody(String.class) .isEqualTo(ConstantUtil.body); } }
此设置须要类路径上的 spring-webflux
。若是您不能或不想添加webflux,Spring Boot 还提供了一个 TestRestTemplate
工具:
/** * 使用运行中的server<br> * 不使用 webflux * * @author YiFeiXi */ @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) public class RandomPortTestRestTemplateTests { @Test public void test(@Autowired TestRestTemplate restTemplate) { String body = restTemplate.getForObject("/", String.class); assertThat(body).isEqualTo(ConstantUtil.body); } }
要自定义 WebTestClient
bean,需配置 WebTestClientBuilderCustomizer
bean。使用用于建立 WebTestClient
的 WebTestClient.Builder
调用任何此类bean。
因为测试上下文框架缓存上下文的缘由,默认状况下禁用JMX以防止相同的组件在同一域上注册。若是此类测试须要访问 MBeanServer
,请考虑将其标记为dirty :
@ExtendWith(SpringExtension.class) @SpringBootTest(properties = "spring.jmx.enabled=true") @DirtiesContext class SampleJmxTests { @Autowired private MBeanServer mBeanServer; @Test void exampleTest() { // ... } }
运行测试时,有时须要在应用程序上下文中模拟某些组件。例如,可能有一个表面覆盖了一些在开发期间不可用的远程服务。当您但愿模拟在实际环境中可能难以触发的故障时,模拟也颇有用。
Spring Boot包含一个 @MockBean
注解,能够用来为 ApplicationContext
中的 bean 定义Mockito 模拟。可使用注解添加新bean或替换单个现有bean定义。注解能够直接用于测试类、测试中的字段或 @Configuration
类和字段。在字段上使用时,建立的模拟的实例也会被注入。模拟bean在每一个测试方法以后自动重置。
若是测试使用了Spring Boot的一个测试注解(例如 @SpringBootTest
),则会自动启用此功能。要将此功能与其余排列一块儿使用,必须显式添加 listener,以下例所示:
@TestExecutionListeners(MockitoTestExecutionListener.class)
下面的示例用模拟实现替换现有的 testService
bean:
@SpringBootTest public class MockBeanTests { @Autowired private TestController testController; @MockBean private TestService testService; @Test public void test(){ given(testService.hello()).willReturn("哈哈"); String hello = testController.hello(); assertThat(hello).isEqualTo("哈哈"); } }
@MockBean
不能用于模拟在应用程序上下文刷新期间执行的bean的行为。在执行测试时,应用程序上下文刷新已经完成,如今配置模拟行为已经太晚了。咱们建议在这种状况下使用 @Bean
方法来建立和配置mock。
另外,您可使用 @SpyBean
来使用 Mockito spy
以包装任何现有的bean
CGLIB代理,如为范围bean建立的代理,将代理方法声明为 final
。这会阻止Mockito正常工做,由于它没法在默认配置中模拟或监视 final 方法。若是想模拟或监视这样的bean,能够经过将 org.mockito:mockito-inline
添加到应用程序的测试依赖项中来配置 Mockito 以使用其内联mock maker。这容许Mockito模拟和监视 final 方法。
虽然Spring的测试框架在测试之间缓存应用程序上下文,并为共享相同配置的测试重用上下文,但使用 @MockBean
或 @SpyBean
会影响缓存键,这极可能会增长上下文的数量。
若是使用 @SpyBean
监视具备按名称引用参数的 @Cacheable
方法的bean,则必须使用 -parameters
编译应用程序。这确保了一旦bean被监视,参数名就可用于缓存基础结构。
Spring Boot的自动配置系统对应用程序运行良好,但有时对测试来讲可能有点太多了。它一般有助于只加载测试应用程序“片断”所需的配置部分。例如,您可能但愿测试Spring MVC控制器是否正确映射了url,而且您不但愿在这些测试中涉及数据库调用,或者您可能但愿测试JPA实体,而且您对运行这些测试时的web层不感兴趣。
spring-boot-test-autoconfigure
模块包括许多注解,能够用来自动配置这些“片断”。它们中的每个都以相似的方式工做,提供一个加载 ApplicationContext
的 @…Test
注解和一个或多个可用于自定义自动配置设置的 @AutoConfigure…
注解。
每一个片断将组件扫描限制为适当的组件,并加载一组很是有限的自动配置类。若是须要排除其中一个,大多数 @…Test
注解都提供 excludeAutoConfiguration
属性。或者,可使用 @ImportAutoConfiguration#exclude
。
不支持在一个测试类中经过使用多个 @...Test
注解来包含多个“片断”。若是须要多个“片断”,请选择其中一个 @…Test
注解并手动包含其余“片断”的 @AutoConfigure…
注解。
也能够将 @AutoConfigure…
注解与标准的 @SpringBootTest
注解一块儿使用。若是对应用程序的“片断”不感兴趣,但须要一些自动配置的测试bean,则可使用此组合。
要测试对象JSON序列化和反序列化是否按预期工做,可使用 @JsonTest
注解。@JsonTest
自动配置可用的受支持JSON mapper,该 mapper 能够是如下库之一:
ObjectMapper
,任何 @JsonComponent
bean 和 任何 Jackson Module
能够在附录中找到@JsonTest启用的自动配置列表。
若是须要配置自动配置的元素,可使用 @AutoConfigureJsonTesters
注解。
Spring Boot包括基于AssertJ的辅助程序,它们与 JSONAssert 和 JsonPath 库一块儿工做,检查JSON是否如预期的那样出现。JacksonTester
、GsonTester
、JsonbTester
和 BasicJsonTester
类能够分别用于Jackson、Gson、Jsonb和字符串。使用 @JsonTest
时,测试类上的任何辅助字段均可以 @Autowired
。如下示例显示了Jackson的测试类:
/** @author YiFeiXi */ @JsonTest public class JsonTests { @Autowired private JacksonTester<UserInfo> json; @Test public void testSerialize() throws Exception { UserInfo u = new UserInfo(1, "张", "三"); assertThat(this.json.write(u)) .isEqualToJson("{\"id\":1,\"firstName\":\"张\",\"lastName\": \"三\"}"); } @Test public void testDeserialize() throws Exception { String content = "{\"firstName\":\"张\",\"lastName\": \"三\"}"; assertThat(this.json.parseObject(content).getFirstName()).isEqualTo("张"); } }
JSON辅助类也能够直接用于标准单元测试。为此,若是不使用 @JsonTest
,请在 @Before
方法中调用辅助类的 initFields
方法。
若是使用Spring Boot的基于AssertJ的辅助程序来 assert 给定JSON路径上的数值,则可能没法根据类型使用isEqualTo。相反,您可使用 AssertJ 的 satisfies
来 assert 该值与给定条件匹配。例如,下面的示例 assert 实际数字是偏移量0.01内接近0.15的浮点值。
assertThat(json.write(message)) .extractingJsonPathNumberValue("@.test.numberValue") .satisfies((number) -> assertThat(number.floatValue()).isCloseTo(0.15f, within(0.01f)));
要测试Spring MVC controllers 是否按预期工做,使用 @WebMvcTest
注解。@WebMvcTest
自动配置Spring MVC基础结构,并将扫描的bean限制为@Controller、@ControllerAdvice、@JsonComponent、Converter、GenericConverter、Filter、HandlerInterceptor、WebMVCConfiguer和HandlerMethodArgumentResolver。使用此注解时,不扫描常规@Component bean。
附录中列出了@WebMvcTest启用的自动配置设置。
若是须要注册额外的组件,好比Jackson模块,能够在测试中使用@import导入额外的配置类。
一般,@WebMvcTest
仅限于一个控制器,并与 @MockBean
结合使用,为所需的协做者提供模拟实现。
@WebMvcTest还自动配置MockMvc。Mock MVC提供了一种快速测试MVC控制器的强大方法,无需启动完整的HTTP服务器。
还能够在非@WebMvcTest(如@SpringBootTest)中使用 @AutoConfigureMockMvc
对MockMvc进行自动配置。如下示例使用MockMvc:
/** @author YiFeiXi */ @WebMvcTest(TestController.class) public class WebMvcTests { @Autowired private MockMvc mvc; @MockBean private TestService testService; @Test public void test() throws Exception { given(this.testService.hello()).willReturn("哈哈"); this.mvc .perform(get("/hello").accept(MediaType.TEXT_PLAIN)) .andExpect(status().isOk()) .andExpect(content().string("哈哈")); } }
若是须要配置自动配置的元素(例如,当应用servlet过滤器时),可使用 @AutoConfigureMockMvc
注解中的属性。
若是使用HtmlUnit或Selenium,自动配置还提供HtmlUnit WebClient
bean 或 Selenium WebDriver
bean。如下示例使用HtmlUnit:
@WebMvcTest(UserVehicleController.class) class MyHtmlUnitTests { @Autowired private WebClient webClient; @MockBean private UserVehicleService userVehicleService; @Test void testExample() throws Exception { given(this.userVehicleService.getVehicleDetails("sboot")) .willReturn(new VehicleDetails("Honda", "Civic")); HtmlPage page = this.webClient.getPage("/sboot/vehicle.html"); assertThat(page.getBody().getTextContent()).isEqualTo("Honda Civic"); } }
默认状况下,Spring Boot 将 WebDriver
bean 放置在一个特殊的“scope”中,以确保在每次测试以后驱动程序退出,并注入新的实例。若是不但愿出现这种行为,能够将 @Scope("singleton")
添加到 WebDriver
@Bean
定义中。
由Spring Boot建立的 webDriver
做用域将替换任何用户定义的同名做用域。若是定义了本身的webDriver做用域,则在使用 @WebMvcTest
时可能会发现它中止工做。
若是类路径上有Spring Security ,@WebMvcTest
还将扫描 WebSecurityConfigurer
bean。可使用Spring Security的测试支持,而不是彻底禁用此类测试的安全性。有关如何使用Spring Security的 MockMvc
支持的更多详细信息,请参见 SpringSecurity 测试操做步骤部分。
要测试Spring WebFlux controllers 是否按预期工做,可使用 @WebFluxTest
注解。@WebFluxTest 自动配置Spring WebFlux基础结构,并将扫描的bean限制为@Controller、@ControllerAdvice、@JsonComponent、Converter、GenericConverter、WebFilter和WebFluxConfigurer。使用@WebFluxTest注解时,不扫描常规@Component bean。
附录中列出了 @WebFluxTest 启用的自动配置。
若是须要注册额外的组件,好比Jackson模块,能够在测试中使用@import导入额外的配置类。
一般,@WebFluxTest 仅限于一个控制器,并与@MockBean注解结合使用,为所需的协做者提供模拟实现。
@WebFluxTest还能够自动配置WebTestClient,这为快速测试WebFlux controllers提供了一种强大的方法,而无需启动完整的HTTP服务器。
还能够在非@WebFluxTest(如@SpringBootTest)中使用@AutoConfigureWebTestClient 注解,从而自动配置web测试客户端。如下示例显示同时使用@WebFluxTest和WebTestClient的类:
/** * WebTestClient<br> * WebTestClient 属于 reactive,设置spring.main.web-application-type=reactive */ @SpringBootTest(properties = "spring.main.web-application-type=reactive") @AutoConfigureWebTestClient public class MockWebTestClientTests { @Test public void test(@Autowired WebTestClient webTestClient) { webTestClient .get() .uri("/") .exchange() .expectStatus() .isOk() .expectBody(String.class) .isEqualTo(ConstantUtil.body); } }
此设置仅受WebFlux应用程序支持,由于在模拟的web应用程序中使用WebTestClient目前仅适用于WebFlux。
@WebFluxTest没法检测经过功能性web框架注册的路由。要在上下文中测试 RouterFunction
bean,请考虑经过@Import或使用@SpringBootTest亲自导入RouterFunction。
@WebFluxTest没法检测经过 SecurityWebFilterChain
类型的@Bean注册的自定义安全配置。要将其包含在测试中,须要经过@import或使用@SpringBootTest导入注册bean的配置。
可使用 @DataJpaTest
注解来测试JPA应用程序。默认状况下,它扫描@Entity类并配置Spring Data JPA repositories。若是类路径上有可用的嵌入式数据库,它也会配置一个。常规@Component bean不会加载到ApplicationContext中。
附录中列出了 @WebFluxTest 启用的自动配置。
默认状况下,Data JPA 测试是事务性的,并在每一个测试结束时回滚。有关更多详细信息,请参阅Spring框架参考文档中的 相关部分。若是这不是你想要的,能够禁用测试或整个类的事务管理,以下所示:
@DataJpaTest @Transactional(propagation = Propagation.NOT_SUPPORTED) class ExampleNonTransactionalTests { }
Data JPA 测试还能够注入一个 TestEntityManager
bean,它提供了一个专门为测试设计的标准 JPA EntityManager
的替代。若是要在 @DataJpaTest
实例以外使用TestEntityManager
,还可使用 @AutoConfigureTestEntityManager
注解。若是须要,还可使用 JdbcTemplate
。如下示例使用了@DataJpaTest注解:
<!-- 内存嵌入式数据库 --> <dependency> <groupId>org.apache.derby</groupId> <artifactId>derby</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
/** @author YiFeiXi */ @DataJpaTest public class DataJpaTests { @Autowired private TestEntityManager entityManager; @Autowired private UserRepository userRepository; @Test public void find() throws Exception { this.entityManager.persist(new UserInfo(1, "张", "三")); UserInfo user = this.userRepository.findByFirstName("张"); assertThat(user.getLastName()).isEqualTo("三"); } }
内存嵌入式数据库一般能够很好地用于测试,由于它们速度快,不须要任何安装。可是,若是但愿对真实数据库运行测试,则可使用 @AutoConfigureTestDatabase
注解,以下例所示:
@DataJpaTest @AutoConfigureTestDatabase(replace=Replace.NONE) class ExampleRepositoryTests { // ... }
@JdbcTest
相似于 @DataJpaTest
,但只用于只须要 DataSource
而不使用 Spring Data JDBC 的测试。默认状况下,它配置内存嵌入式数据库和 JdbcTemplate
。常规@Component bean不会加载到ApplicationContext中。
@Slf4j @JdbcTest public class JdbcTests { @Autowired private JdbcTemplate jdbcTemplate; @Test void test() { jdbcTemplate.execute( "create table user_info(id int primary key, first_name varchar(20), last_name varchar(20))"); jdbcTemplate.execute("insert into user_info(id, first_name, last_name) values(1,'张','三')"); Map<String, Object> user = jdbcTemplate.queryForMap("select * from user_info where id = ?", 1); log.info("{} -> {}", user.get("first_name"), user.get("last_name")); assertThat(user.get("last_name")).isEqualTo("三"); } }
附录中列出了 @WebFluxTest 启用的自动配置。
默认状况下,JDBC测试是事务性的,并在每一个测试结束时回滚。有关更多详细信息,请参阅Spring框架参考文档中的 相关部分。若是这不是您想要的,您能够为测试或整个类禁用事务管理,以下所示:
@JdbcTest @Transactional(propagation = Propagation.NOT_SUPPORTED) class ExampleNonTransactionalTests {}
若是您但愿在真实数据库上运行测试,可使用 @AutoConfigureTestDatabase
注解,方法与对 DataJpaTest
的方法相同。
@DataJdbcTest
相似于 @JdbcTest
,但用于使用 Spring Data JDBC repositories 的测试。默认状况下,它配置内存嵌入式数据库、JdbcTemplate
和 Spring Data JDBC repositories。常规@Component bean不会加载到ApplicationContext中。
附录中列出了 @WebFluxTest 启用的自动配置。
默认状况下,Data JDBC 测试是事务性的,并在每一个测试结束时回滚。若是这不是您想要的,您能够为测试或整个测试类禁用事务管理,如JDBC示例所示。
若是但愿在真实数据库上运行测试,可使用 @AutoConfigureTestDatabase
注解,方法与对DataJpaTest的方法相同。
略
略
略
可使用@DataRedisTest
来测试Redis应用程序。默认状况下,它扫描@RedisHash
类并配置Spring Data Redis repositories。常规@Component bean不会加载到ApplicationContext中。(有关在Spring Boot中使用Redis的更多信息,请参阅本章前面的“ Redis”。)
附录中列出了 @WebFluxTest 启用的自动配置。
如下示例展现了 @DataRedisTest
的使用
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
/** @author YiFeiXi */ @DataRedisTest public class DataRedisTests { @Autowired StringRedisTemplate stringRedisTemplate; @Test void test() { stringRedisTemplate.opsForValue().set("sex", "girl"); } @Test void valueHasSet() { assertThat(stringRedisTemplate.opsForValue().get("sex")).isEqualTo("girl"); } }
略
可使用 @RestClientTest
注解来测试 REST clients。默认状况下,它自动配置Jackson、GSON和Jsonb支持,配置 RestTemplateBuilder
,并添加对 MockRestServiceServer
的支持。常规@Component bean不会加载到ApplicationContext中。
附录中列出了 @WebFluxTest 启用的自动配置。
应该使用 @RestClientTest
的 value
或 components
属性指定要测试的特定bean,以下例所示:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-rest</artifactId> </dependency>
/** @author YiFeiXi */ @RestClientTest public class RestClientTests { private MockRestServiceServer server; @Autowired private RestTemplateBuilder restTemplateBuilder; private TestService testService; @BeforeEach void before() { RestTemplate restTemplate = restTemplateBuilder.build(); testService = new TestService(restTemplate); server = MockRestServiceServer.createServer(restTemplate); } @Test void test() { server.expect(requestTo("/greet")).andRespond(withSuccess("suc", MediaType.TEXT_PLAIN)); assertThat(testService.restReq()).isEqualTo("suc"); } }
可使用 @AutoConfigureRestDocs
注解在 Mock MVC、REST Assured 或WebTestClient 的测试中使用 Spring Rest Docs。它消除了Spring REST Docs 对JUnit扩展的需求。
@AutoConfigureRestDocs
可用于覆盖默认输出目录(若是使用Maven,则为`
target/generated-snippets;若是使用Gradle,则为
build/generated-snippets`)。它还能够用于配置出如今任何文档化uri中的host、
scheme 和 port 。
<dependency> <groupId>org.springframework.restdocs</groupId> <artifactId>spring-restdocs-mockmvc</artifactId> <scope>test</scope> </dependency>
/** @author YiFeiXi */ @WebMvcTest(HelloWorldController.class) @AutoConfigureRestDocs(outputDir = "target/generated-snippets") public class RestDocsTests { @Autowired private MockMvc mockMvc; @Test void hello() throws Exception { this.mockMvc .perform(get("").accept(MediaType.TEXT_PLAIN)) .andExpect(status().isOk()) .andDo(document("list-users")); } }
@AutoConfigureRestDocs
自定义 MockMvc
bean 以使用 Spring REST Docs。可使用 @Autowired
注入它,并在测试中使用它,就像使用Mock MVC和Spring REST Docs 时同样,以下例所示:
@WebMvcTest(UserController.class) @AutoConfigureRestDocs class UserDocumentationTests { @Autowired private MockMvc mvc; @Test void listUsers() throws Exception { this.mvc.perform(get("/users").accept(MediaType.TEXT_PLAIN)) .andExpect(status().isOk()) .andDo(document("list-users")); } }
若是须要比 @AutoConfigureRestDocs
的属性更多地控制Spring REST Docs配置,可使用 RestDocksMockMvcConfigurationCustomizer
bean,以下例所示:
@TestConfiguration static class CustomizationConfiguration implements RestDocsMockMvcConfigurationCustomizer { @Override public void customize(MockMvcRestDocumentationConfigurer configurer) { configurer.snippets().withTemplateFormat(TemplateFormats.markdown()); } }
若是想使用Spring REST Docs对参数化输出目录的支持,能够建立 RestDocumentationResultHandler
bean。自动配置使用此结果处理程序调用 alwaysDo
,从而使每一个 MockMvc
调用自动生成默认代码段。如下示例显示了被定义的RestDocumentationResultHandler
:
@TestConfiguration(proxyBeanMethods = false) static class ResultHandlerConfiguration { @Bean public RestDocumentationResultHandler restDocumentation() { return MockMvcRestDocumentation.document("{method-name}"); } }
@AutoConfigureRestDocs
也能够与 WebTestClient
一块儿使用。可使用 @Autowired
注入它,并在测试中使用它,就像使用 @WebFluxTest
和 Spring REST Docs 时同样,以下例所示:
@WebFluxTest @AutoConfigureRestDocs class UsersDocumentationTests { @Autowired private WebTestClient webTestClient; @Test void listUsers() { this.webTestClient.get().uri("/").exchange().expectStatus().isOk().expectBody() .consumeWith(document("list-users")); } }
若是须要比 @AutoConfigureRestDocs
的属性更多地控制Spring REST Docs配置,可使用 RestDocsWebTestClientConfigurationCustomizer
bean,以下例所示:
@TestConfiguration(proxyBeanMethods = false) public static class CustomizationConfiguration implements RestDocsWebTestClientConfigurationCustomizer { @Override public void customize(WebTestClientRestDocumentationConfigurer configurer) { configurer.snippets().withEncoding("UTF-8"); } }
@AutoConfigureRestDocs
使一个 RequestSpecificatioin
bean(预配置为使用Spring REST Docs)可用于您的测试。您可使用 @Autowired
注入它,并像使用 REST-Assured 和 Spring REST Docs 时同样在测试中使用它,以下例所示:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @AutoConfigureRestDocs class UserDocumentationTests { @Test void listUsers(@Autowired RequestSpecification documentationSpec, @LocalServerPort int port) { given(documentationSpec).filter(document("list-users")).when().port(port).get("/").then().assertThat() .statusCode(is(200)); } }
若是须要比 @AutoConfigureRestDocs
的属性更多地控制Spring REST Docs配置,那么可使用 RestDocsRestAssuredConfigurationCustomizer
bean,以下例所示:
@TestConfiguration(proxyBeanMethods = false) public static class CustomizationConfiguration implements RestDocsRestAssuredConfigurationCustomizer { @Override public void customize(RestAssuredRestDocumentationConfigurer configurer) { configurer.snippets().withTemplateFormat(TemplateFormats.markdown()); } }
每一个片断提供一个或多个 @AutoConfigure…
注解,即定义应该做为片断一部分包含的自动配置。能够经过建立自定义 @AutoConfigure…
注解或向测试添加 @ImportAutoConfiguration
来添加其余自动配置,以下例所示:
@JdbcTest @ImportAutoConfiguration(IntegrationAutoConfiguration.class) class ExampleJdbcTests {}
请确保不要使用常规的@Import 注解来导入自动配置,由于它们是由Spring Boot以特定方式处理的。
若是以合理的方式构造代码,那么默认状况下,@SpringBootApplication
类将用做测试的配置。
所以,重要的是不要在应用程序的主类中添加特定于其功能特定区域的配置设置。
假设使用的是Spring Batch,而且依赖于它的自动配置。能够按以下方式定义 @SpringBootApplication
:
@SpringBootApplication @EnableBatchProcessing public class SampleApplication { //... }
由于这个类是测试的源配置,因此任何片断测试实际上都会尝试启动Spring Batch,这绝对不是您想要作的。建议的方法是将特定于区域的配置移动到与应用程序处于同一级别的单独 @Configuration
类,以下例所示:
@Configuration(proxyBeanMethods = false) @EnableBatchProcessing public class BatchConfiguration { //... }
根据应用程序的复杂性,您能够为您的自定义设置一个单独的 @Configuration 类,也能够为每一个域区域设置一个类。后一种方法容许您在一个测试中启用它,若是须要,可使用@Import 注解。
测试片断从扫描中排除 @Configuration 类。例如,对于 @WebMvcTest
,如下配置不会在测试片断加载的应用程序上下文中包含给定的 WebMvcConfigurer
bean:
@Configuration public class WebConfiguration { @Bean public WebMvcConfigurer testConfigurer() { return new WebMvcConfigurer() { //... }; } }
可是,下面的配置将致使测试片断加载自定义 WebMvcConfiguer
。
@Component public class TestWebMvcConfigurer implements WebMvcConfigurer { //... }
另外一个混乱的来源是类路径扫描。假设,当您以合理的方式构造代码时,您须要扫描另外一个包。您的应用程序可能相似于如下代码:
@SpringBootApplication @ComponentScan({"com.example.app", "org.acme.another"}) public class SampleApplication{ //... }
这样作有效地覆盖了默认的组件扫描指令,其反作用是扫描这两个包,而不考虑您选择的片断。例如,@DataJpaTest
彷佛忽然扫描应用程序的组件和用户配置。一样,将自定义指令移动到单独的类是解决此问题的好方法。
若是这不适合,能够在测试层次结构中的某个位置建立@SpringBootConfiguration,以便使用它。或者,能够为测试指定一个 source,这将禁用查找默认源的行为。
若是但愿使用Spock测试一个Spring Boot 应用,那么应该在应用程序的构建中添加对Spock的 spock-spring
模块的依赖。spock-spring
将Spring的测试框架集成到 Spock 中。建议使用Spock 1.2或更高版本,以从Spock的Spring框架和SpringBoot集成的许多改进中获益。有关更多详细信息,请参阅Spock的Spring模块的文档。
当测试应用程序类打包为spring boot的一部分时,一些在测试应用程序一般是有用的。
ConfigFileApplicationContextInitializer
是一个 ApplicationContextInitializer
,能够将其应用于测试加载 Spring Boot application.properties
文件。当不须要@SpringBootTest提供的全套功能时,可使用它,以下例所示:
@ContextConfiguration(classes = Config.class, initializers = ConfigFileApplicationContextInitializer.class)
单独使用 ConfigFileApplicationContextInitializer
不支持 @Value(${…})
注入。它的惟一工做是确保 application.properties
文件加载到Spring的环境中。对于 @Value
支持,须要另外配置 PropertySourcesPlaceholderConfigurer
或使用 @SpringBootTest
,后者会自动配置一个。
/** @author YiFeiXi */ @Configuration public class UserConfig { @Bean public UserInfo defaultUserInfo() { return new UserInfo(1, "张", "三"); } }
/** @author YiFeiXi */ @ExtendWith(SpringExtension.class) @ContextConfiguration( classes = UserConfig.class, initializers = ConfigFileApplicationContextInitializer.class) public class ConfigFileTests { @Autowired private UserInfo userInfo; @Test void test() { assertThat(userInfo.getFirstName()).isEqualTo("张"); assertThat(userInfo.getLastName()).isEqualTo("三"); } }
TestPropertyValues
容许快速将属性添加到 ConfigurableEnvironment
或ConfigurableApplicationContext
。可使用 key=value
字符串调用它,以下所示:
/** @author YiFeiXi */ @SpringBootTest public class TestPropertyValueTests { @Autowired private ConfigurableEnvironment environment; @Test void test() { TestPropertyValues.of("org=spring", "name=boot").applyTo(environment); String org = environment.getProperty("org"); String name = environment.getProperty("name"); assertThat(org).isEqualTo("spring"); assertThat(name).isEqualTo("boot"); } }
OutputCapture
是一个JUnit扩展,可用于捕获 System.out
和 System.err
输出。添加 @ExtendWith(OutputCaptureExtension.class)
并将 CapturedOutput
做为参数注入测试类构造函数或测试方法来使用,以下所示:
/** * 输出捕捉 * * @author YiFeiXi */ @ExtendWith(OutputCaptureExtension.class) public class OutputCaptureTests { @Test void test(CapturedOutput output) { System.out.print("hello world!"); assertThat(output).isEqualTo("hello world!"); } }
TestRestTemplate
是Spring的 RestTemplate
的一个方便的替代品,它在集成测试中很是有用。您能够获得一个普通模板或一个发送基本HTTP身份验证的模板(带有用户名和密码)。在这两种状况下,模板都以测试友好的方式运行,不会在服务器端错误上引起异常。
Spring Framework 5.0提供了一个新的WebTestClient,可用于WebFlux集成测试以及WebFlux和MVC端到端测试。它为断言提供了一个流畅的API,与 TestRestTemplate 不一样。
建议使用ApacheHTTP客户端(4.3.2或更高版本),但不是强制的。若是在类路径中有,TestRestTemplate 将经过适当配置 client 来响应。若是您确实使用了Apache的HTTP客户端,则会启用一些附加的测试友好功能:
TestRestTemplate
能够在集成测试中直接实例化,以下例所示:
/** @author YiFeiXi */ @SpringBootTest(webEnvironment = WebEnvironment.NONE) public class RestTemplateTests { @Test void test() { TestRestTemplate template = new TestRestTemplate(); String responseBody = template.getForObject("http://127.0.0.1:8080/", String.class); assertThat(responseBody).isEqualTo("Hello World!"); } }
或者,若是将 @SpringBootTest
注解与 WebEnvironment.RANDOM_PORT
或 WebEnvironment.DEFINED_PORT
一块儿使用,则能够插入彻底配置的 TestRestTemplate
并开始使用它。若是须要,能够经过 RestTemplateBuilder
bean应用其余定制。任何未指定 host 和 port 的URL都会自动链接到嵌入式服务器,以下例所示:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) class SampleWebClientTests { @Autowired private TestRestTemplate template; @Test void testRequest() { HttpHeaders headers = this.template.getForEntity("/example", String.class).getHeaders(); assertThat(headers.getLocation()).hasHost("other.example.com"); } @TestConfiguration(proxyBeanMethods = false) static class Config { @Bean RestTemplateBuilder restTemplateBuilder() { return new RestTemplateBuilder().setConnectTimeout(Duration.ofSeconds(1)) .setReadTimeout(Duration.ofSeconds(1)); } } }
官方文档
代码示例
公众号:逸飞兮(专一于 Java 领域知识的深刻学习,从源码到原理,系统有序的学习)