テストユーティリティ

アプリケーションのテスト時に一般的に役立ついくつかのテストユーティリティクラスは、spring-boot の一部としてパッケージ化されています。

ConfigDataApplicationContextInitializer

ConfigDataApplicationContextInitializer は、Spring Boot application.properties ファイルをロードするテストに適用できる ApplicationContextInitializer です。次の例に示すように、@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")
	}

}

OutputCapture

OutputCapture は、System.out および System.err 出力をキャプチャーするために使用できる JUnit Extension です。これを使用するには、次のように @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 は、WebFlux 統合テストおよび WebFlux および MVC のエンドツーエンドテストの両方で機能する新しい WebTestClient を提供します。TestRestTemplate とは異なり、アサーションのための流れるような API を提供します。

Apache HTTP クライアント (バージョン 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.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")
	}

}

あるいは、WebEnvironment.RANDOM_PORT または WebEnvironment.DEFINED_PORT で @SpringBootTest アノテーションを使用する場合、完全に構成された 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.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().setConnectTimeout(Duration.ofSeconds(1))
				.setReadTimeout(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().setConnectTimeout(Duration.ofSeconds(1))
				.setReadTimeout(Duration.ofSeconds(1))
		}

	}

}