How to create a WSResponse object from string for Play WSClient
Asked Answered
C

3

5

Documentation suggests testing API client based on WSClient using a mock web service, that is, create a play.server.Server which will respond to real HTTP requests.

I would prefer to create WSResponse objects directly from files, complete with status line, header lines and body, without real TCP connections. That would require less dependencies and run faster. Also there may be other cases when this is useful.

But I can't find a simple way to do it. It seems all implementations wrapped by WSResponse are tied to reading from network.

Should I just create my own subclass of WSResponse for this, or maybe I'm wrong and it already exists?

Congreve answered 12/1, 2016 at 20:50 Comment(3)
You have to used Play WSClient ? You could checkout Resitio Mock framework for testing. I would advice, Developer already creating all this class, take that class as .jar and create mock service out of it.Uturn
@BostonStar Yes, I'm bound to WSClient. We use junit+mockito. How will Resito help creating WSResponse objects?Congreve
I think you can direct access original object and create mock service.Uturn
R
5

The API for Play seems intentionally obtuse. You have to use their "Cacheable" classes, which are the only ones that seem directly instantiable from objects you'd have lying around.

This should get you started:

import play.api.libs.ws.ahc.AhcWSResponse;
import play.api.libs.ws.ahc.cache.CacheableHttpResponseBodyPart;
import play.api.libs.ws.ahc.cache.CacheableHttpResponseHeaders;
import play.api.libs.ws.ahc.cache.CacheableHttpResponseStatus;
import play.shaded.ahc.io.netty.handler.codec.http.DefaultHttpHeaders;
import play.shaded.ahc.org.asynchttpclient.Response;
import play.shaded.ahc.org.asynchttpclient.uri.Uri;

AhcWSResponse response = new AhcWSResponse(new Response.ResponseBuilder()
        .accumulate(new CacheableHttpResponseStatus(Uri.create("uri"), 200, "status text", "protocols!"))
        .accumulate(new CacheableHttpResponseHeaders(false, new DefaultHttpHeaders().add("My-Header", "value")))
        .accumulate(new CacheableHttpResponseBodyPart("my body".getBytes(), true))
        .build());

The mystery boolean values aren't documented. My guess is the boolean for BodyPart is whether that is the last part of the body. My guess for Headers is whether the headers are in the trailer of a message.

Recreant answered 6/12, 2017 at 17:3 Comment(4)
Thanks for the response! Quite indirect solution, but having nothing better built-in, I accept this.Congreve
Yeah, I still haven't gotten it to parse correctly. The cryptic error message hasn't helped, so I factored this out so I can actually test things.Recreant
This did not work for me. For some reason, I cannot find CacheableHttpResponseHeaders, usng Play 2.5Fairyfairyland
I think it's new in 2.6 playframework.com/documentation/2.6.0-M4/api/scala/…Recreant
R
3

I used another way, mocking WSResponse with Mockito:

import play.libs.ws.WSRequest;
import play.libs.ws.WSResponse;
import org.mockito.Mockito;

...

          final WSResponse wsResponseMock = Mockito.mock(WSResponse.class);
          Mockito.doReturn(200).when(wsResponseMock).getStatus();
          final String jsonStr = "{\n"
                  + "  \"response\": {\n"
                  + "    \"route\": [\n"
                  + "      { \"summary\" :\n"
                  + "        {\n"
                  + "          \"distance\": 23\n"
                  + "        }\n"
                  + "      }\n"
                  + "    ]\n"
                  + "  }\n"
                  + "}";
          ObjectMapper mapper = new ObjectMapper();
          JsonNode jsonNode = null;
          try {
            jsonNode = mapper.readTree(jsonStr);
          } catch (IOException e) {
            e.printStackTrace();
          }
          Mockito.doReturn(
                  jsonNode)
              .when(wsResponseMock)
              .asJson();
Rondelet answered 5/4, 2019 at 14:50 Comment(2)
You can use play.libs.Json#parse(String) instead of creating an object mapper. Also, it is advisable to use when(..).thenReturn(..) instead of doReturn(..).when(..). Upvoted.Ingrained
The downside of this solution is that one needs to mock all expected calls instead of using external resources or a convenient response building API.Congreve
A
3

If you are using play-framework 2.8.x and scala, the below code can help us generate a dummy WSResponse:

import play.api.libs.ws.ahc.AhcWSResponse
import play.api.libs.ws.ahc.cache.CacheableHttpResponseStatus
import play.shaded.ahc.org.asynchttpclient.Response
import play.shaded.ahc.org.asynchttpclient.uri.Uri
import play.api.libs.ws.ahc.cache.CacheableHttpResponseBodyPart
import play.shaded.ahc.io.netty.handler.codec.http.DefaultHttpHeaders

class OutputWriterSpec extends FlatSpec with Matchers {
  val respBuilder = new Response.ResponseBuilder()
  respBuilder.accumulate(new CacheableHttpResponseStatus(Uri.create("http://localhost:9000/api/service"), 202, "status text", "json"))
  respBuilder.accumulate(new DefaultHttpHeaders().add("Content-Type", "application/json"))
  respBuilder.accumulate(new CacheableHttpResponseBodyPart("{\n\"id\":\"job-1\",\n\"lines\": [\n\"62812ce276aa9819a2e272f94124d5a1\",\n\"13ea8b769685089ba2bed4a665a61fde\"\n]\n}".getBytes(), true))
  val resp = new AhcWSResponse(respBuilder.build())

  val outputWriter = OutputWriter

  val expected = ("\"job-1\"", List("\"62812ce276aa9819a2e272f94124d5a1\"", "\"13ea8b769685089ba2bed4a665a61fde\""), "_SUCCESS")
  "Output Writer" should "handle response from api call" in {
    val actual = outputWriter.handleResponse(resp, "job-1")
    println("the actual : " + actual)
    actual shouldEqual(expected)

  }
}
Atelier answered 27/6, 2020 at 19:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.