RestTestClient

RestTestClient は、サーバーアプリケーションのテスト用に設計された HTTP クライアントです。Spring の RestClient をラップし、リクエストの実行に使用しますが、レスポンスの検証用にテストファサードを公開しています。RestTestClient はエンドツーエンドの HTTP テストに使用できます。また、MockMvc を介して、サーバーを実行せずに Spring MVC アプリケーションをテストすることもできます。

セットアップ

RestTestClient をセットアップするには、バインドするサーバー設定を選択する必要があります。これは、MockMvc の複数の設定から選択することも、ライブサーバーへの接続を選択することもできます。

コントローラーにバインド

この設定により、サーバーを実行せずに、モックリクエストおよびレスポンスオブジェクトを介して特定のコントローラーをテストできます。

  • Java

  • Kotlin

RestTestClient client =
		RestTestClient.bindToController(new TestController()).build();
val client = RestTestClient.bindToController(TestController()).build()

ApplicationContext にバインド

このセットアップにより、Spring MVC インフラストラクチャとコントローラー宣言を使用して Spring 構成を読み込み、サーバーを実行せずに、モックリクエストおよびレスポンスオブジェクトを介してリクエストを処理できるようになります。

  • Java

  • Kotlin

@SpringJUnitConfig(WebConfig.class) (1)
class MyTests {

	RestTestClient client;

	@BeforeEach
	void setUp(ApplicationContext context) {  (2)
		client = RestTestClient.bindToApplicationContext(context).build(); (3)
	}
}
1 ロードする構成を指定します
2 構成を注入する
3RestTestClient を作成する
@SpringJUnitConfig(WebConfig::class) (1)
class MyTests {

	lateinit var client: RestTestClient

	@BeforeEach
	fun setUp(context: ApplicationContext) { (2)
		client = RestTestClient.bindToApplicationContext(context).build() (3)
	}
}
1 ロードする構成を指定します
2 構成を注入する
3RestTestClient を作成する

ルーター関数にバインド

この設定により、サーバーを実行せずに、モックリクエストオブジェクトとレスポンスオブジェクトを介して関数エンドポイントをテストできます。

  • Java

  • Kotlin

RouterFunction<?> route = ...
client = RestTestClient.bindToRouterFunction(route).build();
val route: RouterFunction<*> = ...
val client = RestTestClient.bindToRouterFunction(route).build()

サーバーにバインド

このセットアップは、実行中のサーバーに接続して、完全なエンドツーエンドの HTTP テストを実行します。

  • Java

  • Kotlin

client = RestTestClient.bindToServer().baseUrl("http://localhost:8080").build();
client = RestTestClient.bindToServer().baseUrl("http://localhost:8080").build()

クライアント構成

前述のサーバー設定オプションに加えて、ベース URL、デフォルトヘッダー、クライアントフィルターなど、クライアントオプションも設定できます。これらのオプションは、最初の bindTo 呼び出しの直後から、以下のようにすぐに利用できます。

  • Java

  • Kotlin

client = RestTestClient.bindToController(new TestController())
		.baseUrl("/test")
		.build();
client = RestTestClient.bindToController(TestController())
		.baseUrl("/test")
		.build()

テストの作成

RestClient と RestTestClient は、exchange() の呼び出しまでは API は同じです。その後、RestTestClient はレスポンスを検証するための 2 つの代替方法を提供します。

  1. 組み込みアサーションは、期待される チェーンに基づいてリクエストワークフローを継承します。

  2. AssertJ 統合は assertThat() ステートメントを介してレスポンスを検証します

組み込みアサーション

To use the built-in assertions, remain in the workflow after the call to exchange(), and use one of the expectation methods. For example:

  • Java

  • Kotlin

client.get().uri("/persons/1")
	.accept(MediaType.APPLICATION_JSON)
	.exchange()
	.expectStatus().isOk()
	.expectHeader().contentType(MediaType.APPLICATION_JSON);
client.get().uri("/persons/1")
	.accept(MediaType.APPLICATION_JSON)
	.exchange()
	.expectStatus().isOk()
	.expectHeader().contentType(MediaType.APPLICATION_JSON)

いずれかが失敗した場合でもすべての期待値を表明したい場合は、複数のチェーン化された expect*(..) 呼び出しの代わりに expectAll(..) を使用できます。この機能は、AssertJ でのソフトアサーションのサポートおよび JUnit Jupiter での assertAll() のサポートに似ています。

  • Java

  • Kotlin

client.get().uri("/persons/1")
	.accept(MediaType.APPLICATION_JSON)
	.exchange()
	.expectAll(
		spec -> spec.expectStatus().isOk(),
		spec -> spec.expectHeader().contentType(MediaType.APPLICATION_JSON)
	);
client.get().uri("/persons/1")
	.accept(MediaType.APPLICATION_JSON)
	.exchange()
	.expectAll(
		{ spec -> spec.expectStatus().isOk() },
		{ spec -> spec.expectHeader().contentType(MediaType.APPLICATION_JSON) }
	)

次に、次のいずれかを使用してレスポンス本文をデコードすることを選択できます。

  • expectBody(Class<T>): 単一のオブジェクトにデコードします。

  • expectBody(): JSON コンテンツまたは空のボディの場合は byte[] にデコードします。

組み込みのアサーションが不十分な場合は、代わりにオブジェクトを使用して、他のアサーションを実行できます。

  • Java

  • Kotlin

client.get().uri("/persons/1")
        .exchange()
        .expectStatus().isOk()
        .expectBody(Person.class)
        .consumeWith(result -> {
            // custom assertions (for example, AssertJ)...
        });
client.get().uri("/persons/1")
		.exchange()
		.expectStatus().isOk()
		.expectBody<Person>()
		.consumeWith {
			// custom assertions (for example, AssertJ)...
		}

または、ワークフローを終了して EntityExchangeResult を取得することもできます。

  • Java

  • Kotlin

EntityExchangeResult<Person> result = client.get().uri("/persons/1")
		.exchange()
		.expectStatus().isOk()
		.expectBody(Person.class)
		.returnResult();
val result = client.get().uri("/persons/1")
		.exchange()
		.expectStatus().isOk
		.expectBody<Person>()
		.returnResult()
ジェネリクスを使用してターゲット型にデコードする必要がある場合は、Class<T> ではなく ParameterizedTypeReference (Javadoc) を受け入れるオーバーロードメソッドを探します。

コンテンツなし

レスポンスに内容が含まれることが予想されない場合は、次のように主張できます。

  • Java

  • Kotlin

client.post().uri("/persons")
		.body(person)
		.exchange()
		.expectStatus().isCreated()
		.expectBody().isEmpty();
client.post().uri("/persons")
		.body(person)
		.exchange()
		.expectStatus().isCreated()
		.expectBody().isEmpty()

レスポンスコンテンツを無視する場合、以下はアサーションなしでコンテンツをリリースします。

  • Java

  • Kotlin

client.get().uri("/persons/123")
		.exchange()
		.expectStatus().isNotFound()
		.expectBody(Void.class);
client.get().uri("/persons/123")
		.exchange()
		.expectStatus().isNotFound
		.expectBody<Unit>()

JSON コンテンツ

ターゲット型なしで expectBody() を使用して、高レベルのオブジェクトを介してではなく、生のコンテンツに対してアサーションを実行できます。

JSONAssert (英語) で完全な JSON コンテンツを確認するには:

  • Java

  • Kotlin

client.get().uri("/persons/1")
		.exchange()
		.expectStatus().isOk()
		.expectBody()
		.json("{\"name\":\"Jane\"}")
client.get().uri("/persons/1")
		.exchange()
		.expectStatus().isOk()
		.expectBody()
		.json("{\"name\":\"Jane\"}")

JSONPath [GitHub] (英語) で JSON コンテンツを確認するには:

  • Java

  • Kotlin

client.get().uri("/persons")
		.exchange()
		.expectStatus().isOk()
		.expectBody()
		.jsonPath("$[0].name").isEqualTo("Jane")
		.jsonPath("$[1].name").isEqualTo("Jason");
client.get().uri("/persons")
		.exchange()
		.expectStatus().isOk()
		.expectBody()
		.jsonPath("$[0].name").isEqualTo("Jane")
		.jsonPath("$[1].name").isEqualTo("Jason")

AssertJ 統合

RestTestClientResponse は AssertJ 統合のメインエントリポイントです。これは、assertThat() 文の使用を可能にするために、交換の ResponseSpec をラップする AssertProvider です。例:

  • Java

  • Kotlin

ResponseSpec spec = client.get().uri("/persons").exchange();

RestTestClientResponse response = RestTestClientResponse.from(spec);
assertThat(response).hasStatusOk();
assertThat(response).hasContentTypeCompatibleWith(MediaType.TEXT_PLAIN);
// ...
val spec = client.get().uri("/persons").exchange()

val response = RestTestClientResponse.from(spec)
assertThat(response).hasStatusOk()
assertThat(response).hasContentTypeCompatibleWith(MediaType.TEXT_PLAIN)
// ...

最初に組み込みワークフローを使用し、その後 ExchangeResult を取得して AssertJ でラップし、続行することもできます。例:

  • Java

  • Kotlin

ExchangeResult result = client.get().uri("/persons").exchange()
		. // ...
		.returnResult();

RestTestClientResponse response = RestTestClientResponse.from(result);
assertThat(response).hasStatusOk();
assertThat(response).hasContentTypeCompatibleWith(MediaType.TEXT_PLAIN);
// ...
val result = client.get().uri("/persons").exchange()
		. // ...
		.returnResult()

val response = RestTestClientResponse.from(spec)
assertThat(response).hasStatusOk()
assertThat(response).hasContentTypeCompatibleWith(MediaType.TEXT_PLAIN)
// ...