Reputation: 9103
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
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
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