2013-05-16 12 views
15

Ich habe ein einfaches Spray-Client verspotten:Wie Spray-Client-Antwort

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

Voll Code kann here gefunden werden.

Ich möchte die Antwort des Servers zum Testen der Logik in den Success und Failure Fällen spotten. Die einzige relevante Information, die ich fand, war here, aber ich war nicht in der Lage, das Kuchenmuster zu verwenden, um die sendReceive Methode zu verspotten.

Jeder Vorschlag oder Beispiel würde sehr geschätzt werden.

Antwort

19

Hier ist ein Beispiel für eine Möglichkeit, es mit specs2 für die Testspezifikation und Mockito für die Spott zu verspotten. Zuerst Refactoring das Main Objekt in ein Klasse-Setup für spöttisch:

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

Dann die Testspezifikation:

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 
    } 
    } 
} 

Also mein Ansatz war hier zunächst eine überwindbare Funktion im sendAndReceive genannt ElevationClient zu definieren, delegiert nur an die spray sendReceive funktion. In der Testspezifikation überschreibe ich dann die sendAndReceive-Funktion, um eine Funktion zurückzugeben, die ein vollständiges Future zurückgibt, das einen Schein HttpResponse einwickelt. Dies ist ein Ansatz, um das zu tun, was Sie tun möchten. Ich hoffe das hilft.

+0

Genau das, was ich gesucht habe. Danke! – Eleni

+2

Wir könnten einfach eine 'Future.successful (mockResponse)' anstelle von 'Promise.successful (mockResponse) .future' verwenden. Ich würde auch lieber 'sendAndReceive' ein Argument für' ElevationClient' anstelle von override machen. Dann würden wir für unseren "sendAndReceive" eine falsche 'Funktion2 [HttpRequest, Future [HttpResponse]]' übergeben. – Alden

11

Es gibt keine Notwendigkeit, in diesem Fall spöttisch einzuführen, wie man einfach ein Httpresponse viel leichter mit der bestehenden API aufbauen können:

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

(Sorry für dieses Posting als eine andere Antwort, aber nicht haben genug Karma zu kommentieren)