跳到主要内容
版本:4.0.2

Test Utilities

QWen Max 中英对照 Test Utilities

一些在测试应用程序时通常很有用的测试工具类被打包在 spring-boot 中。

ConfigDataApplicationContextInitializer

ConfigDataApplicationContextInitializer 是一个 ApplicationContextInitializer,你可以将其应用于测试中,以加载 Spring Boot 的 application.properties 文件。当你不需要 @SpringBootTest 提供的完整功能集时,可以使用它,如下例所示:

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 可让你快速向 ConfigurableEnvironmentConfigurableApplicationContext 添加属性。你可以使用 key=value 字符串调用它,如下所示:

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");
}

}

OutputCaptureExtension

OutputCaptureExtension 是一个 JUnit Extension,可用于捕获 System.outSystem.err 的输出。要使用它,请添加 @ExtendWith(OutputCaptureExtension.class),并将 CapturedOutput 作为参数注入到你的测试类构造函数或测试方法中,如下所示:

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");
}

}

TestRestTemplate

TestRestTemplate 是 Spring 的 RestTemplate 的一个便捷替代方案,适用于集成测试。它由 spring-boot-resttestclient 模块提供。同时还需要添加对 spring-boot-restclient 的依赖。在添加此依赖时需谨慎,因为它会启用 RestClient.Builder 的自动配置。如果你的主代码中使用了 RestClient.Builder,请将 spring-boot-restclient 依赖声明在应用程序的主 classpath 中,而不仅仅是在测试 classpath 中。

你可以获取一个普通模板,或者一个发送 Basic HTTP 认证(带用户名和密码)的模板。无论哪种情况,该模板都具有容错性。这意味着它在测试时表现友好,不会在遇到 4xx 和 5xx 错误时抛出异常。相反,可以通过返回的 ResponseEntity 及其状态码来检测此类错误。

如果你需要流畅的断言 API,可以考虑使用 RestTestClient,它适用于 mock 环境端到端测试

如果你正在使用 Spring WebFlux,请考虑使用 WebTestClient,它提供了类似的 API,并且适用于 mock 环境WebFlux 集成测试 以及 端到端测试

建议(但非强制)使用 Apache HTTP Client(版本 5.1 或更高)。如果你的 classpath 中包含该客户端,TestRestTemplate 会相应地配置客户端。如果你确实使用了 Apache 的 HTTP 客户端,它会被配置为忽略 Cookie(从而使模板保持无状态)。

TestRestTemplate 可以在你的集成测试中直接实例化,如下例所示:

import org.junit.jupiter.api.Test;

import org.springframework.boot.resttestclient.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
}

}

或者,如果你使用 @SpringBootTest 注解并配合 WebEnvironment.RANDOM_PORTWebEnvironment.DEFINED_PORT,可以通过在测试类上添加 @AutoConfigureTestRestTemplate 注解来注入一个完全配置好的 TestRestTemplate。如有必要,还可以通过 RestTemplateBuilder Bean 进行额外的自定义配置。

任何未指定主机和端口的 URL 会自动连接到嵌入式服务器,如下例所示:

import java.time.Duration;

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.restclient.RestTemplateBuilder;
import org.springframework.boot.resttestclient.TestRestTemplate;
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;
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.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)
@AutoConfigureTestRestTemplate
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));
}

}

}