0

如果我需要通过 spray-can 编写涉及 HTTP 请求的集成测试,我如何确保 spray-can 正在使用 CallingThreadDispatcher?

目前以下演员将打印None

class Processor extends Actor {
  override def receive = {
    case Msg(n) =>
      val response = (IO(Http) ? HttpRequest(GET, Uri("http://www.google.com"))).mapTo[HttpResponse]
      println(response.value)
  }
}

如何确保请求在与测试相同的线程上执行(导致同步请求)?

4

1 回答 1

1

由于您不模拟“Google”,因此进行集成内部测试似乎是一种奇怪的方式,因此更像是集成外部测试和同步TestActorRef在这里不太适合。控制喷雾内螺纹的要求也非常棘手。但是,如果您真的需要它来进行 http-request - 这是可能的。在一般情况下,您必须在您的application.conf

  • “manager-dispatcher”(来自 Http.scala)来调度你的IO(Http) ? req
  • “host-connector-dispatcher”由HttpHostConnector(或ProxyHttpHostConnector)实际调度您的请求使用它
  • “设置组调度程序”为Http.Connect

它们都在喷雾文档的配置部分中进行了描述。它们都指向“akka.actor.default-dispatcher”(请参阅​​ Dispatchers),因此您可以通过更改这个来更改所有这些。

这里的问题是调用线程实际上并不能保证是你的线程,所以它对你的测试没有多大帮助。想象一下,如果一些参与者注册了一些处理程序,响应您的消息:

  //somewhere in spray...
  case r@Request => registerHandler(() => {
      ...
      sender ! response
  })

响应可能是从另一个线程发送的,因此response.value可能仍None处于当前状态。实际上,响应将从底层套接字库的侦听线程发送,独立于您的测试线程。简单地说,请求可能会在一个(您的)线程中发送,但响应会在另一个线程中接收。

如果您真的需要在这里阻止,我建议您将此类代码示例(如IO(Http) ? HttpRequest)移出并在测试中以任何方便的方式模拟它们。像这样发送:

trait AskGoogle {
   def okeyGoogle = IO(Http) ? HttpRequest(GET, Uri("http://www.google.com"))).mapTo[HttpResponse] 
}

trait AskGoogleMock extends AskGoogle {
   def okeyGoogle = Await.result(super.okeyGoogle, timeout)
}

class Processor extends Actor with AskGoogle {
  override def receive = {
    case Msg(n) =>
      val response = okeyGoogle
      println(response.value)
  }
}

val realActor = system.actorOf(Props[Processor])
val mockedActor = TestActorRef[Processor with AskGoogleMock]

顺便说一句,您可以IO(HTTP)与另一个TestActorRef自定义actor模拟,它将为您执行外部请求 - 如果您有一个大项目,它应该需要最少的代码更改。

于 2015-03-01T15:57:17.380 回答