2013-05-16 6 views
15

을 조롱하는 방법 :나는 간단한 스프레이 클라이언트가 스프레이 클라이언트 응답

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

전체 코드가 here를 찾을 수 있습니다.

SuccessFailure 개의 로직을 테스트하기 위해 서버의 응답을 모의하고 싶습니다. 내가 찾은 유일한 관련 정보는 here 이었지만 cake 패턴을 사용하여 sendReceive 메소드를 조롱하지 못했습니다.

모든 제안이나 예를 들어 주시면 감사하겠습니다.

답변

19

다음은 테스트 사양에 specs2를 사용하고 조롱을 위해 mockito를 사용하여 조롱하는 방법 중 하나입니다. 첫째, Main 객체는 조롱에 대한 클래스 설정에 리팩토링 :

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

그런 다음, 테스트 사양 :

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

그래서 내 방법은 여기 처음 sendAndReceive라는 ElevationClient의 재정의 함수를 정의하는 것이라고 그냥 스프레이 sendReceive 기능을 위임합니다. 그런 다음 테스트 스펙에서 sendAndReceive 함수를 오버라이드하여 Future을 모방 한 HttpResponse을 반환하는 함수를 반환합니다. 이것은 당신이하고 싶은 것을하기위한 하나의 접근법입니다. 이게 도움이 되길 바란다.

+0

정확히 내가 무엇을 찾고 있었습니까. 고마워! – Eleni

+2

우리는 단지'Promise.successful (mockResponse) .future' 대신에'Future.successful (mockResponse)'를 사용할 수 있습니다. 오히려 override를 사용하는 대신'sendAndReceive'를'ElevationClient'에 인자를 주려고합니다. 그런 다음 우리의'sendAndReceive'에 대한 모의 함수'Function2 [HttpRequest, Future [HttpResponse]]를 전달할 것입니다. – Alden

11

당신은 단순히 HttpResponse에 훨씬 더 쉽게 사용하는 기존의 API 구축 할 수 있습니다이 경우에 조롱 소개 할 필요가 없습니다 : 다른 답변으로 이것을 게시

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

(죄송합니다,하지만이 없습니다 의견을 말하기에 충분한 카르마)