Reputation: 7795
Say we have an instance of o.s.w.reactive.function.server.ServerResponse
.
What is the proper way to fetch the contents of its body, in other words how to implement fetchBodyAsString
function?
test(){
ServerResponse response = getResponseFromService("mock data");
String body = fetchBodyAsString(response);
assertEquals("hello", body);
}
Could you also elaborate a bit on why does ServerResponse
have methods for everything (cookies(), headers(), statusCode()
), but the response body? I guess there should be a way to get the body with writeTo()
method, although it is absolutely vague how to use it.
Upvotes: 10
Views: 13366
Reputation: 24857
Another way to test the body inside a unit test is to cast the ServerResponse
to an EntityResponse
. This does show a warning for an unchecked cast but inside a controlled unit test I wasn't too worried about it. This just exposes the object that was set using bodyValue()
before it is serialized. If you are trying to test the serialization of said body this might not work for your needs.
val entityResponse = serverResponse as EntityResponse<{ Insert Class of Body }>
val bodyObject = entityResponse.entity()
Upvotes: 1
Reputation: 1430
This is based on Alan Yeung solution above, except in Java. There has to be a better 'native' way to do this without loading application context.
public class ServerResponseExtractor {
public static <T> T serverResponseAsObject(ServerResponse serverResponse,
ObjectMapper mapper, Class<T> type) {
String response = serverResponseAsString(serverResponse);
try {
return mapper.readValue(response, type);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static String serverResponseAsString(ServerResponse serverResponse) {
MockServerWebExchange exchange = MockServerWebExchange.from(
MockServerHttpRequest.get("/foo/foo"));
DebugServerContext debugServerContext = new DebugServerContext();
serverResponse.writeTo(exchange, debugServerContext).block();
MockServerHttpResponse response = exchange.getResponse();
return response.getBodyAsString().block();
}
private static class DebugServerContext implements ServerResponse.Context {
@Override
public List<HttpMessageWriter<?>> messageWriters() {
return HandlerStrategies.withDefaults().messageWriters();
}
@Override
public List<ViewResolver> viewResolvers() {
return Collections.emptyList();
}
}
}
Upvotes: 1
Reputation: 300
I was digging around for something similar for unit testing purposes, and stitched together the below code. It's in Kotlin, but should be relatively easy to translate to Java and solve your problem (though it definitely does seem a bit hacky).
fun fetchBodyAsString(serverResponse: ServerResponse): String {
val DEFAULT_CONTEXT: ServerResponse.Context = object : ServerResponse.Context {
override fun messageWriters(): List<HttpMessageWriter<*>> {
return HandlerStrategies.withDefaults().messageWriters()
}
override fun viewResolvers(): List<ViewResolver> {
return Collections.emptyList()
}
}
// Only way I could figure out how to get the ServerResponse body was to have it write to an exchange
val request = MockServerHttpRequest.get("http://thisdoenstmatter.com").build()
val exchange = MockServerWebExchange.from(request)
serverResponse.writeTo(exchange, DEFAULT_CONTEXT).block()
val response = exchange.response
return response.bodyAsString.block()!!
}
Basically needed to create a fake MockServerWebExchange
and have the ServerResponse
write to it to translate it into a MockServerHttpResponse
of which you can pull the response body out of fairly painlessly. This is definitely not elegant, but it works.
Also note, I didn't test the above function itself, just that it compiles. It should work though as the function's inner code is exactly what we're using.
As for your other questions about ServerResponse
, I don't know the answers, but am curious about that as well!
Upvotes: 9
Reputation: 51
As far as i know ServerResponse is used at the controller or router function. For testing you can use WebTestClient
@Autowired
WebTestClient webTestClient;
@Test
void test() {
webTestClient.get()
.exchange()
.expectStatus()
.isOk()
.expectHeader()
.contentType(MediaType.APPLICATION_JSON)
.expectBody()
.jsonPath("data.name").isEqualTo("name");
}
or
@Autowired
WebTestClient webTestClient;
@Test
void test() {
FluxExchangeResult<String> result = webTestClient.get()
.exchange()
.returnResult(String.class);
int rawStatusCode = result.getRawStatusCode();
HttpStatus status = result.getStatus();
HttpHeaders responseHeaders = result.getResponseHeaders();
String stringResponseBody = result.getResponseBody().blockFirst();
}
Upvotes: 5