Randomize
Randomize

Reputation: 9103

Akka-Http: How to TestProbe a request

I have a request whose response depends on an actor reply. I am trying to test it in this way:

val myActor:TestProbe = TestProbe()

val route = new MyRoute() {
    override def myServiceActor:ActorRef = {
        myActor.ref
    }
}.route

"return a query result for GET" in {
    Get("/foo") ~> route ~> check {
        myActor.expectMsg(ExecuteFoo())
        myActor.reply(FOO)
        responseEntity shouldEqual toJsonEntity(RequestResult(FOO))
    }
}

I get correctly that expectMsg is verified but the reply is asynchronous respect to the responseEntity check. In this case the test fails.

Is there a way to wait for the reply?

Upvotes: 4

Views: 461

Answers (2)

cmbaxter
cmbaxter

Reputation: 35463

You're on the right track using a TestProbe. The key is to separate the combination of running the request and then checking it (which you are doing as 1 step via check) into two explicit steps. First run it, then do any stubbing on the TestProbe and lastly, make your checks. The updated code for your sample would look like this:

  val result = Get("/foo") ~> route ~> runRoute
  myActor.expectMsg(ExecuteFoo())
  myActor.reply(FOO)

  check {
      responseEntity shouldEqual toJsonEntity(RequestResult(FOO))
  }(result)

You can see there that I'm first using runRoute to simple run the route without performing any checks. I assign this value to result as I will need this later to perform any checks. Then, you can safely do your stubbing against the TestProbe. At this point, it's already received the message and is waiting for your calls to verify what message it got and how to respond. Then, when done with that, we can call check, passing an explicit result (the one from runRoute) to that call instead of relying on an implicit.

If you follow this approach, you should be able to properly test routes that call an actor, using a TestProbe to do so.

Upvotes: 6

hveiga
hveiga

Reputation: 6925

One way of doing this (which might not be the right one or the only one) is using AutoPilot. Here is an example:

val myProbe = TestProbe()
myProbe.setAutoPilot(new TestActor.AutoPilot {
  def run(sender: ActorRef, msg: Any) = msg match {
    case ExecuteFoo(_) =>
      //do something else if needed
      sender ! FOO
      TestActor.NoAutoPilot
  }
})

Upvotes: 0

Related Questions