如何模拟喷涂客户端响应

Ele*_*eni 15 unit-testing scala spray 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()
}
Run Code Online (Sandbox Code Playgroud)

完整代码可以在这里找到.

我想模拟服务器的响应来测试SuccessFailure案例中的逻辑.我找到的唯一相关信息是在这里,但我无法使用蛋糕模式来模拟sendReceive方法.

任何建议或例子将不胜感激.

cmb*_*ter 19

下面是使用specs2作为测试规范并使用mockto进行模拟的一种方法.首先,将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()
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,测试规范:

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
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

所以我的方法是首先在被ElevationClient调用sendAndReceive中定义一个可覆盖的函数,该函数只是委托给spray sendReceive函数.然后,在测试规范中,我重写该sendAndReceive函数以返回一个返回完成的Future包装模拟的函数HttpResponse.这是做你想做的事情的一种方法.我希望这有帮助.

  • 我们可以使用`Future.successful(mockResponse)`而不是`Promise.successful(mockResponse).future`.我还宁愿将`sendAndReceive`作为`ElevationClient`的参数,而不是使用override.然后我们将为`sendAndReceive`传递一个模拟`Function2 [HttpRequest,Future [HttpResponse]]`. (2认同)

Jos*_*lez 11

在这种情况下没有必要引入模拟,因为您可以使用现有的API更轻松地构建HttpResponse:

val mockResponse = HttpResponse(StatusCodes.OK, HttpEntity(ContentTypes.`application/json`, json.getBytes))
Run Code Online (Sandbox Code Playgroud)

(很抱歉将此作为另一个答案发布,但没有足够的业力来评论)