|
此版本仍在开发中,尚未视为稳定版。如需最新稳定版本,请使用 Spring Boot 4.0.4! |
测试工具
一些在测试应用程序时通常很有用的测试工具类被打包在 spring-boot 中。
ConfigDataApplicationContextInitializer
ConfigDataApplicationContextInitializer 是一个 ApplicationContextInitializer,您可以将其应用于测试以加载 Spring Boot application.properties 文件。
当您不需要 @SpringBootTest 提供的全部功能时,可以使用它,如下例所示:
-
Java
-
Kotlin
import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer;
import org.springframework.test.context.ContextConfiguration;
@ContextConfiguration(classes = Config.class, initializers = ConfigDataApplicationContextInitializer.class)
class MyConfigFileTests {
// ...
}
import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer
import org.springframework.test.context.ContextConfiguration
@ContextConfiguration(classes = [Config::class], initializers = [ConfigDataApplicationContextInitializer::class])
class MyConfigFileTests {
// ...
}
单独使用 ConfigDataApplicationContextInitializer 并不提供对 @Value("${…}") 注入的支持。
它的唯一作用是确保将 application.properties 文件加载到 Spring 的 Environment 中。
若要获得 @Value 支持,您需要额外配置一个 PropertySourcesPlaceholderConfigurer,或者使用 @SpringBootTest,后者会为您自动配置一个。 |
TestPropertyValues
TestPropertyValues 可让您快速向 ConfigurableEnvironment 或 ConfigurableApplicationContext 添加属性。
您可以使用 key=value 字符串调用它,如下所示:
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
class MyEnvironmentTests {
@Test
void testPropertySources() {
MockEnvironment environment = new MockEnvironment();
TestPropertyValues.of("org=Spring", "name=Boot").applyTo(environment);
assertThat(environment.getProperty("name")).isEqualTo("Boot");
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.boot.test.util.TestPropertyValues
import org.springframework.mock.env.MockEnvironment
class MyEnvironmentTests {
@Test
fun testPropertySources() {
val environment = MockEnvironment()
TestPropertyValues.of("org=Spring", "name=Boot").applyTo(environment)
assertThat(environment.getProperty("name")).isEqualTo("Boot")
}
}
OutputCaptureExtension
OutputCaptureExtension 是一个 JUnit Extension,可用于捕获 System.out 和 System.err 输出。
要使用它,请添加 @ExtendWith(OutputCaptureExtension.class) 并将 CapturedOutput 作为参数注入到您的测试类构造函数或测试方法中,如下所示:
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;
import static org.assertj.core.api.Assertions.assertThat;
@ExtendWith(OutputCaptureExtension.class)
class MyOutputCaptureTests {
@Test
void testName(CapturedOutput output) {
System.out.println("Hello World!");
assertThat(output).contains("World");
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.boot.test.system.CapturedOutput
import org.springframework.boot.test.system.OutputCaptureExtension
@ExtendWith(OutputCaptureExtension::class)
class MyOutputCaptureTests {
@Test
fun testName(output: CapturedOutput?) {
println("Hello World!")
assertThat(output).contains("World")
}
}
TestRestTemplate
TestRestTemplate 是 Spring 的 RestTemplate 的一个便捷替代方案,在集成测试中非常有用。
您可以获取一个基础模板,或一个发送基本 HTTP 身份验证(包含用户名和密码)的模板。
无论哪种情况,该模板都具备容错能力。
这意味着它以对测试友好的方式运行,不会在遇到 4xx 和 5xx 错误时抛出异常。
相反,此类错误可以通过返回的 ResponseEntity 及其状态码进行检测。
Spring Framework 5.0 提供了一个新的 WebTestClient,适用于 WebFlux 集成测试 以及 WebFlux 和 MVC 的端到端测试。
它提供了用于断言的流畅 API,这与 TestRestTemplate 不同。 |
建议使用 Apache HTTP Client(5.1 或更高版本),但并非强制要求。
如果您的类路径中包含该库,TestRestTemplate 将通过适当配置客户端来响应。
如果您使用 Apache 的 HTTP 客户端,它将被配置为忽略 Cookie(从而使模板保持无状态)。
TestRestTemplate 可以在您的集成测试中直接实例化,如下例所示:
-
Java
-
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import static org.assertj.core.api.Assertions.assertThat;
class MyTests {
private final TestRestTemplate template = new TestRestTemplate();
@Test
void testRequest() {
ResponseEntity<String> response = this.template.getForEntity("https://myhost.example.com/example",
String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
// Other assertions to verify the response
}
}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.boot.test.web.client.TestRestTemplate
import org.springframework.http.HttpStatus
class MyTests {
private val template = TestRestTemplate()
@Test
fun testRequest() {
val response = template.getForEntity("https://myhost.example.com/example", String::class.java)
assertThat(response.statusCode).isEqualTo(HttpStatus.OK)
// Other assertions to verify the response
}
}
或者,如果您将 @SpringBootTest 注解与 WebEnvironment.RANDOM_PORT 或 WebEnvironment.DEFINED_PORT 一起使用,则可以注入一个完全配置好的 TestRestTemplate 并立即开始使用。
如有必要,可以通过 RestTemplateBuilder Bean 应用额外的自定义设置。
任何未指定主机和端口的 URL 都会自动连接到嵌入式服务器,如下例所示:
-
Java
-
Kotlin
import java.time.Duration;
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.context.TestConfiguration;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MySpringBootTests {
@Autowired
private TestRestTemplate template;
@Test
void testRequest() {
ResponseEntity<String> response = this.template.getForEntity("/example", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
// Other assertions to verify the response
}
@TestConfiguration(proxyBeanMethods = false)
static class RestTemplateBuilderConfiguration {
@Bean
RestTemplateBuilder restTemplateBuilder() {
return new RestTemplateBuilder().connectTimeout(Duration.ofSeconds(1)).readTimeout(Duration.ofSeconds(1));
}
}
}
import org.assertj.core.api.Assertions.assertThat
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.context.TestConfiguration
import org.springframework.boot.test.web.client.TestRestTemplate
import org.springframework.boot.web.client.RestTemplateBuilder
import org.springframework.context.annotation.Bean
import org.springframework.http.HttpStatus
import java.time.Duration
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MySpringBootTests(@Autowired val template: TestRestTemplate) {
@Test
fun testRequest() {
val response = template.getForEntity("/example", String::class.java)
assertThat(response.statusCode).isEqualTo(HttpStatus.OK)
// Other assertions to verify the response
}
@TestConfiguration(proxyBeanMethods = false)
internal class RestTemplateBuilderConfiguration {
@Bean
fun restTemplateBuilder(): RestTemplateBuilder {
return RestTemplateBuilder().connectTimeout(Duration.ofSeconds(1))
.readTimeout(Duration.ofSeconds(1))
}
}
}