此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Boot 3.4.0spring-doc.cn

测试实用程序

在测试应用程序时通常有用的一些测试实用程序类打包为 的一部分。spring-bootspring-doc.cn

ConfigDataApplicationContextInitializer

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

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 不支持注入。 它唯一的工作是确保将文件加载到 Spring 的 Environment 中。 对于@Value支持,你需要额外配置PropertySourcesPlaceholderConfigurer或使用@SpringBootTest,它会自动为你配置一个。@Value("${…​}")application.properties

TestPropertyValues

TestPropertyValues 允许您快速将属性添加到 ConfigurableEnvironmentConfigurableApplicationContext。 您可以使用字符串调用它,如下所示:key=valuespring-doc.cn

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 扩展,可用于捕获 System.outSystem.err 输出。 要使用它,请将 CapturedOutput 作为参数添加并注入到您的测试类构造函数或测试方法中,如下所示:@ExtendWith(OutputCaptureExtension.class)spring-doc.cn

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的便捷替代方案,在集成测试中很有用。 你可以获取一个 vanilla 模板或发送 Basic HTTP 身份验证的模板(带有用户名和密码)。 在任一情况下,模板都是容错的。 这意味着它的行为对测试友好,不会在 4xx 和 5xx 错误上引发异常。 相反,可以通过返回的 ResponseEntity 及其状态代码来检测此类错误。spring-doc.cn

Spring Framework 5.0 提供了一个新的 WebTestClient,它适用于 WebFlux 集成测试以及 WebFlux 和 MVC 端到端测试。 它与 TestRestTemplate 不同,它为断言提供了流畅的 API。

建议使用 Apache HTTP 客户端(版本 5.1 或更高版本),但并非强制性要求。 如果你在 Classpath 上有它,则TestRestTemplate通过适当地配置客户端来做出响应。 如果您确实使用 Apache 的 HTTP 客户端,则会启用一些其他测试友好功能:spring-doc.cn

  • 不遵循重定向(因此您可以断言响应位置)。spring-doc.cn

  • Cookie 将被忽略(因此模板是无状态的)。spring-doc.cn

TestRestTemplate可以直接在集成测试中实例化,如以下示例所示:spring-doc.cn

import org.junit.jupiter.api.Test;

import org.springframework.boot.test.web.client.TestRestTemplate;
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> headers = this.template.getForEntity("https://myhost.example.com/example", String.class);
		assertThat(headers.getHeaders().getLocation()).hasHost("other.example.com");
	}

}
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.boot.test.web.client.TestRestTemplate

class MyTests {

	private val template = TestRestTemplate()

	@Test
	fun testRequest() {
		val headers = template.getForEntity("https://myhost.example.com/example", String::class.java)
		assertThat(headers.headers.location).hasHost("other.example.com")
	}

}

或者,如果您将 @SpringBootTest 注释与 或 一起使用,则可以注入完全配置的 TestRestTemplate 并开始使用它。 如有必要,可以通过RestTemplateBuilder bean 应用其他自定义。 任何未指定主机和端口的 URL 都会自动连接到嵌入式服务器,如以下示例所示:WebEnvironment.RANDOM_PORTWebEnvironment.DEFINED_PORTspring-doc.cn

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.HttpHeaders;

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MySpringBootTests {

	@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 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 java.time.Duration

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MySpringBootTests(@Autowired val template: TestRestTemplate) {

	@Test
	fun testRequest() {
		val headers = template.getForEntity("/example", String::class.java).headers
		assertThat(headers.location).hasHost("other.example.com")
	}

	@TestConfiguration(proxyBeanMethods = false)
	internal class RestTemplateBuilderConfiguration {

		@Bean
		fun restTemplateBuilder(): RestTemplateBuilder {
			return RestTemplateBuilder().connectTimeout(Duration.ofSeconds(1))
				.readTimeout(Duration.ofSeconds(1))
		}

	}

}