简体   繁体   中英

How to get body as String from ServerResponse for test?

Say we have an instance of oswreactive.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.

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();

}

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!

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();
    }
  }

}

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()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM