Akka IO和TestActorRef

时间:2015-03-01 08:46:20

标签: scala akka spray spray-client

如果我需要通过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)
  }
}

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

1 个答案:

答案 0 :(得分:1)

进行集成内部测试似乎很奇怪,因为你不会嘲笑" Google"所以更像是集成外部测试和同步TestActorRef没有&#39非常适合这里。控制喷涂内螺纹的要求也相当棘手。但是,如果您确实需要http请求 - 它是可能的。一般情况下,您必须在application.conf

中设置多个调度程序
  • "管理器,调度员" (来自Http.scala)发送你的IO(Http) ? req
  • "主机连接器调度"实际发送您的请求的HttpHostConnector(或ProxyHttpHostConnector)使用它
  • "设置基的调度" Http.Connect

所有这些都在Configuration Section喷雾文件中描述。他们都指向" akka.actor.default-dispatcher" (参见Dispatchers),因此您可以通过更改此更改来更改所有这些内容。

这里的问题是调用线程实际上并不保证你的线程,所以它对你的测试没有多大帮助。试想一下,如果一些演员注册了一些处理程序,请回复你的消息:

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

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

如果你真的需要在这里阻止,我会建议你移动这些代码样本(如IO(Http) ? HttpRequest)并在测试中以任何方便的方式模拟它们。这样的Smtng:

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,它会为您执行外部请求 - 如果您有一个大项目,则应该需要最少的代码更改。< / p>