Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock spray-client response

I have a simple spray client :

val pipeline = sendReceive ~> unmarshal[GoogleApiResult[Elevation]]

val responseFuture = pipeline {Get("http://maps.googleapis.com/maps/api/elevation/jsonlocations=27.988056,86.925278&sensor=false") }

responseFuture onComplete {
  case Success(GoogleApiResult(_, Elevation(_, elevation) :: _)) =>
    log.info("The elevation of Mt. Everest is: {} m", elevation)
    shutdown()

  case Failure(error) =>
    log.error(error, "Couldn't get elevation")
    shutdown()
}

Full code can be found here.

I want to mock the response of the server to test the logic in the Success and Failure cases. The only relevant information i found was here but I haven't been able to use the cake pattern to mock the sendReceive method.

Any suggestion or example would be greatly appreciated.

like image 256
Eleni Avatar asked May 16 '13 10:05

Eleni


2 Answers

Here's an example of one way to mock it using specs2 for the test spec and mockito for the mocking. First, the Main object refactored into a class setup for mocking:

class ElevationClient{
  // we need an ActorSystem to host our application in
  implicit val system = ActorSystem("simple-spray-client")
  import system.dispatcher // execution context for futures below
  val log = Logging(system, getClass)

  log.info("Requesting the elevation of Mt. Everest from Googles Elevation API...")

  import ElevationJsonProtocol._
  import SprayJsonSupport._

  def sendAndReceive = sendReceive

  def elavation = {
    val pipeline = sendAndReceive ~> unmarshal[GoogleApiResult[Elevation]]

    pipeline {
      Get("http://maps.googleapis.com/maps/api/elevation/json?locations=27.988056,86.925278&sensor=false")
    }   
  }


  def shutdown(): Unit = {
    IO(Http).ask(Http.CloseAll)(1.second).await
    system.shutdown()
  }
}

Then, the test spec:

class ElevationClientSpec extends Specification with Mockito{

  val mockResponse = mock[HttpResponse]
  val mockStatus = mock[StatusCode]
  mockResponse.status returns mockStatus
  mockStatus.isSuccess returns true

  val json = """
    {
       "results" : [
          {
             "elevation" : 8815.71582031250,
             "location" : {
                "lat" : 27.9880560,
                "lng" : 86.92527800000001
             },
             "resolution" : 152.7032318115234
          }
       ],
       "status" : "OK"
    }    
    """

  val body = HttpEntity(ContentType.`application/json`, json.getBytes())
  mockResponse.entity returns body

  val client = new ElevationClient{
    override def sendAndReceive = {
      (req:HttpRequest) => Promise.successful(mockResponse).future
    }
  }

  "A request to get an elevation" should{
    "return an elevation result" in {
      val fut = client.elavation
      val el = Await.result(fut, Duration(2, TimeUnit.SECONDS))
      val expected = GoogleApiResult("OK",List(Elevation(Location(27.988056,86.925278),8815.7158203125)))
      el mustEqual expected
    }
  }
}

So my approach here was to first define an overridable function in the ElevationClient called sendAndReceive that just delegates to the spray sendReceive function. Then, in the test spec, I override that sendAndReceive function to return a function that returns a completed Future wrapping a mock HttpResponse. This is one approach for doing what you want to do. I hope this helps.

like image 111
cmbaxter Avatar answered Sep 16 '22 22:09

cmbaxter


There's no need to introduce mocking in this case, as you can simply build a HttpResponse much more easily using the existing API:

val mockResponse = HttpResponse(StatusCodes.OK, HttpEntity(ContentTypes.`application/json`, json.getBytes))

(Sorry for posting this as another answer, but don't have enough karma to comment)

like image 27
José González Avatar answered Sep 17 '22 22:09

José González