测试工具

一些测试工具类通常在测试你的应用时很有用,是作为Spring靴.spring-doc.cadn.net.cn

ConfigDataApplicationContextInitializer

ConfigDataApplicationContextInitializer应用上下文初始化器你可以应用到测试中来加载 Spring Bootapplication.properties文件。 当你不需要 S 提供的所有功能时,你可以使用它@SpringBootTest如下例所示:spring-doc.cadn.net.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单靠这点无法提供支持@Value(“${...}”)注射。 它的唯一职责就是确保application.properties文件已加载到 Spring 的环境. 为@Value支持,你需要额外配置PropertySourcesPlaceholderConfigurer或使用@SpringBootTest,它会自动为你配置一个。

测试属性值

测试属性值这样可以快速向可配置环境ConfigurableApplicationContext. 你可以用key=value字符串,具体如下:spring-doc.cadn.net.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输出。 要使用它,请添加@ExtendWith(OutputCaptureExtension.class)并注入捕获输出作为你测试类构造器或测试方法的论证,具体如下:spring-doc.cadn.net.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")
	}

}

测试休息模板

测试休息模板是Spring的便利替代品Rest模板这在积分测试中非常有用。 它由spring-boot-resttestclient模块。spring-doc.cadn.net.cn

你可以用原版模板,或者发送基础HTTP认证(带有用户名和密码)的模板。 无论哪种情况,模板都是容错的。 这意味着它以友好测试的方式表现,不对4xx和5xx错误抛弃异常。 相反,这些错误可以通过返回的响应实体以及它的状态代码。spring-doc.cadn.net.cn

如果你需要流利的 API 来进行断言,可以考虑使用RestTestClient它适用于模拟环境端到端测试spring-doc.cadn.net.cn

如果你正在使用 Spring WebFlux,请考虑WebTestClient它提供类似的API,并支持模拟环境WebFlux集成测试端到端测试spring-doc.cadn.net.cn

建议但非强制使用Apache HTTP 客户端(版本5.1或更高版本)。 如果你的职业路径里有这个,那测试休息模板通过适当配置客户端来响应。 如果你用的是Apache的HTTP客户端,它配置为忽略Cookie(所以模板是无状态的)。spring-doc.cadn.net.cn

测试休息模板可以直接在你的积分测试中实例化,如下示例所示:spring-doc.cadn.net.cn

import org.junit.jupiter.api.Test;

import org.springframework.boot.resttestclient.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.resttestclient.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注释WebEnvironment.RANDOM_PORTWebEnvironment.DEFINED_PORT,你可以注入一个完全配置的测试休息模板通过对测试类进行注释,记载为@AutoConfigureTestRestTemplate. 如有必要,还可以通过Rest模板构建器豆。spring-doc.cadn.net.cn

任何未指定主机和端口的URL会自动连接到嵌入服务器,如下示例所示:spring-doc.cadn.net.cn

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

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

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureTestRestTemplate
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.restclient.RestTemplateBuilder
import org.springframework.boot.resttestclient.TestRestTemplate
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate
import org.springframework.context.annotation.Bean
import java.time.Duration

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureTestRestTemplate
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))
		}

	}

}