2013-05-16 13 views
15

Ho un semplice client spruzzo:Come deridere risposta spray-cliente

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

codice completo può essere trovato here.

Voglio prendere in giro la risposta del server per testare la logica nei casi Success e Failure. L'unica informazione rilevante che ho trovato è stata here ma non sono stato in grado di utilizzare il modello di torta per deridere il metodo sendReceive.

Qualsiasi suggerimento o esempio sarebbe molto apprezzato.

risposta

19

Ecco un esempio di un modo per deriderlo usando specs2 per le specifiche di test e mockito per il beffardo. In primo luogo, l'oggetto Main riscritta in una configurazione di classe per beffardo:

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

Poi, il 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 
    } 
    } 
} 

Quindi il mio approccio era quello di definire prima una funzione di override nel ElevationClient chiamato sendAndReceive che solo delega alla funzione spray sendReceive. Quindi, nelle specifiche del test, ignoro la funzione sendAndReceive per restituire una funzione che restituisce un Future completato con un simulato HttpResponse. Questo è un approccio per fare ciò che vuoi fare. Spero che aiuti.

+0

Esattamente quello che stavo cercando. Grazie! – Eleni

+2

Potremmo semplicemente usare 'Future.successful (mockResponse)' invece di 'Promise.successful (mockResponse) .future'. Vorrei anche rendere 'sendAndReceive' un argomento a' ElevationClient' invece di usare override. Poi passeremmo in una simulazione 'Function2 [HttpRequest, Future [HttpResponse]]' per il nostro 'sendAndReceive'. – Alden

11

Non c'è bisogno di introdurre beffardo in questo caso, come si può semplicemente costruire un HttpResponse molto più facilmente utilizzando l'API esistente:

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

(Ci scusiamo per questo distacco da un'altra risposta, ma non hanno abbastanza karma per commentare)