Skip to content

Commit a23c377

Browse files
committed
Docs for the RestTestClient AssertJ integration
Closes gh-35701
1 parent d63f1a8 commit a23c377

File tree

2 files changed

+92
-12
lines changed

2 files changed

+92
-12
lines changed

framework-docs/modules/ROOT/pages/testing/resttestclient.adoc

Lines changed: 84 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -173,13 +173,20 @@ Kotlin::
173173
[[resttestclient-tests]]
174174
== Writing Tests
175175

176-
`RestTestClient` provides an API identical to xref:integration/rest-clients.adoc#rest-restclient[`RestClient`]
177-
up to the point of performing a request by using `exchange()`.
176+
xref:integration/rest-clients.adoc#rest-restclient[`RestClient`] and `RestTestClient` have
177+
the same API up to the point of the call to `exchange()`. After that, `RestTestClient`
178+
provides two alternative ways to verify the response:
178179

179-
After the call to `exchange()`, `RestTestClient` diverges from `RestClient`, and
180-
instead continues with a workflow to verify responses.
180+
1. xref:resttestclient-workflow[Built-in Assertions] extend the request workflow with a chain of expectations
181+
2. xref:resttestclient-assertj[AssertJ Integration] to verify the response via `assertThat()` statements
181182

182-
To assert the response status and headers, use the following:
183+
184+
185+
[[resttestclient-workflow]]
186+
=== Built-in Assertions
187+
188+
To use the built-in assertions, remain in the workflow after the call to `exchange()`, and
189+
use one of the expectation methods. For example:
183190

184191
[tabs]
185192
======
@@ -243,7 +250,7 @@ Kotlin::
243250
You can then choose to decode the response body through one of the following:
244251

245252
* `expectBody(Class<T>)`: Decode to single object.
246-
* `expectBody()`: Decode to `byte[]` for xref:testing/resttestclient.adoc#resttestclient-json[JSON Content] or an empty body.
253+
* `expectBody()`: Decode to `byte[]` for xref:testing/resttestclient.adoc#resttestclient-workflow-json[JSON Content] or an empty body.
247254

248255

249256
If the built-in assertions are insufficient, you can consume the object instead and
@@ -310,9 +317,8 @@ that accept {spring-framework-api}/core/ParameterizedTypeReference.html[`Paramet
310317
instead of `Class<T>`.
311318

312319

313-
314-
[[resttestclient-no-content]]
315-
=== No Content
320+
[[resttestclient-workflow-no-content]]
321+
==== No Content
316322

317323
If the response is not expected to have content, you can assert that as follows:
318324

@@ -367,9 +373,8 @@ Kotlin::
367373
======
368374

369375

370-
371-
[[resttestclient-json]]
372-
=== JSON Content
376+
[[resttestclient-workflow-json]]
377+
==== JSON Content
373378

374379
You can use `expectBody()` without a target type to perform assertions on the raw
375380
content rather than through higher level Object(s).
@@ -432,3 +437,70 @@ Kotlin::
432437

433438

434439

440+
[[resttestclient-assertj]]
441+
=== AssertJ Integration
442+
443+
`RestTestClientResponse` is the main entry point for the AssertJ integration.
444+
It is an `AssertProvider` that wraps the `ResponseSpec` of an exchange in order to enable
445+
use of `assertThat()` statements. For example:
446+
447+
[tabs]
448+
======
449+
Java::
450+
+
451+
[source,java,indent=0,subs="verbatim,quotes"]
452+
----
453+
ResponseSpec spec = client.get().uri("/persons").exchange();
454+
455+
RestTestClientResponse response = RestTestClientResponse.from(spec);
456+
assertThat(response).hasStatusOk();
457+
assertThat(response).hasContentTypeCompatibleWith(MediaType.TEXT_PLAIN);
458+
// ...
459+
----
460+
461+
Kotlin::
462+
+
463+
[source,kotlin,indent=0,subs="verbatim,quotes"]
464+
----
465+
val spec = client.get().uri("/persons").exchange()
466+
467+
val response = RestTestClientResponse.from(spec)
468+
assertThat(response).hasStatusOk()
469+
assertThat(response).hasContentTypeCompatibleWith(MediaType.TEXT_PLAIN)
470+
// ...
471+
----
472+
======
473+
474+
You can also use the built-in workflow first, and then obtain an `ExchangeResult` to wrap
475+
and continue with AssertJ. For example:
476+
477+
[tabs]
478+
======
479+
Java::
480+
+
481+
[source,java,indent=0,subs="verbatim,quotes"]
482+
----
483+
ExchangeResult result = client.get().uri("/persons").exchange()
484+
. // ...
485+
.returnResult();
486+
487+
RestTestClientResponse response = RestTestClientResponse.from(result);
488+
assertThat(response).hasStatusOk();
489+
assertThat(response).hasContentTypeCompatibleWith(MediaType.TEXT_PLAIN);
490+
// ...
491+
----
492+
493+
Kotlin::
494+
+
495+
[source,kotlin,indent=0,subs="verbatim,quotes"]
496+
----
497+
val result = client.get().uri("/persons").exchange()
498+
. // ...
499+
.returnResult()
500+
501+
val response = RestTestClientResponse.from(spec)
502+
assertThat(response).hasStatusOk()
503+
assertThat(response).hasContentTypeCompatibleWith(MediaType.TEXT_PLAIN)
504+
// ...
505+
----
506+
======

spring-test/src/main/java/org/springframework/test/web/servlet/client/RestTestClient.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,14 @@ interface RequestHeadersSpec<S extends RequestHeadersSpec<S>> {
514514

515515
/**
516516
* Perform the exchange.
517+
* <p>The returned spec may be used in one of two alternative ways:
518+
* <ul>
519+
* <li>Use methods on the spec to extend the request workflow with a
520+
* chain of response expectations
521+
* <li>Wrap the spec with
522+
* {@link org.springframework.test.web.servlet.client.assertj.RestTestClientResponse#from(ResponseSpec)}
523+
* and verify the response with AssertJ statements
524+
* </ul>
517525
* @return a spec for expectations on the response
518526
*/
519527
ResponseSpec exchange();

0 commit comments

Comments
 (0)