Reputation: 12896
With Spring Boot 2.4.2 I'm using the WebTestClient
to invoke requests in my integration tests.
This is the first request which gets a list of messages:
webTestClient
.get()
.uri("/api/messages")
.headers(http -> http.setBearerAuth(token))
.exchange()
.expectStatus().isOk()
.expectHeader().contentType(APPLICATION_JSON)
.expectBody()
.jsonPath("$.length()").isEqualTo(1)
.jsonPath("$[0].id").isNumber()
.jsonPath("$[0].type").isEqualTo(4);
Now I'd like to invoke a subsequent request to download a specific message. For this, I need the id
which was already checked with jsonPath("$[0].id")
.
webTestClient
.get()
.uri(uriBuilder -> uriBuilder.path("/api/messages/{id}").build(extractedId))
.headers(http -> http.setBearerAuth(token))
.exchange()
.expectStatus().isOk();
How can I extract this id
into a local variable or else, so that it's available for the second request?
Upvotes: 5
Views: 19748
Reputation: 448
Use value(Consumer<T> consumer)
on .jsonPath("<path>")
result and "consume" the value of the JSON field into a variable.
Kotlin code below:
var testId = ""
webClient.post()
.uri("/api/test")
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(testPostBodyString))
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus().is2xxSuccessful
.expectBody()
.jsonPath("$.testId").isNotEmpty()
.jsonPath("$.testId").value<String> { testId = it}
Upvotes: 1
Reputation: 96
I encountered the same problem, and this is the solution I came up with.
According to documentation,
WebTestClient is a thin shell around WebClient, using it to perform requests and exposing a dedicated, fluent API for verifying responses.
To my understanding it is geared for testing the response in a similar fashion as assertThat
assertations do.
In my solution I instead use WebClient
for extracting values.
The code snippet below should explain all the details. Note that it is just a generalized example, you should tailor it for your needs.
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import static org.springframework.http.MediaType.APPLICATION_JSON;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class FooTest {
@Autowired
private WebTestClient webTestClient;
/**
* The port of the server. It starts on a RANDOM_PORT. @LocalServerPort is a way to find out what this port is.
*/
@LocalServerPort
private int port;
@Test
void someTestMethod() throws JSONException {
// Create the request body that we'll send with the POST request.
String postRequestBody = new JSONObject()
.put("JsonField_1", "value a")
.put("JsonFiled_2", "value b")
// .put("any_additional_json_fields", "with_any_values")
.toString();
// The URI where we'll send the request to.
String postRequestUri = "http://localhost:" + String.valueOf(port) + "/some_api";
// Send a POST request, and save the response.
TypeOfResponseWeExpect response = WebClient.create()
.post()
.uri(postRequestUri)
.contentType(APPLICATION_JSON)
.accept(APPLICATION_JSON)
.body(BodyInserters.fromValue(postRequestBody))
.retrieve()
.bodyToMono(TypeOfResponseWeExpect.class)
.block();
// And now we can extract any values from the response.
long extractedId = response.getId();
String token = response.getToken();
FooField fooField = response.getFoo();
BarField barField = response.getBar();
// Now we can use the extracted id field, or any field from the response.
webTestClient
.get()
.uri(uriBuilder -> uriBuilder.path("/api/messages/{id}").build(extractedId))
.headers(http -> http.setBearerAuth(token))
.exchange()
.expectStatus().isOk();
}
}
Edit: After some further tries, I found a way to extract the response with WebTestClient too:
TypeOfResponseWeExpect response = this.webTestClient
.post()
.uri(postRequestUri)
.contentType(APPLICATION_JSON)
.accept(APPLICATION_JSON)
.body(BodyInserters.fromValue(postRequestBody))
.exchange()
.expectBody(TypeOfResponseWeExpect.class)
.returnResult()
.getResponseBody();
Upvotes: 2
Reputation: 1920
You can check their official docs for it.
But expanding the answer a bit, easiest way would be this
val result = webTestClient
.get()
.uri(uriBuilder -> uriBuilder.path("/api/messages/{id}").build(extractedId))
.headers(http -> http.setBearerAuth(token))
.exchange()
.expectStatus().isOk()
.returnResult();
There are also ways to get an (infinite) stream of responses explained on docs, which is pretty similar to the example above.
Upvotes: 6