In my scenario I have 2 actors:
watchee
(I useTestProbe
)watcher
(Watcher
wrapped intoTestActorRef
to expose some internalstate
I track in my test)
Watcher should take some actions when watchee
dies.
Here is the complete test case I've written so far:
class TempTest(_system: ActorSystem) extends TestKit(_system) with ImplicitSender with FunSuiteLike with Matchers with BeforeAndAfterAll {
def this() = this(ActorSystem("TempTest"))
override def afterAll {
TestKit.shutdownActorSystem(system)
}
class WatcherActor(watchee: ActorRef) extends Actor {
var state = "initial"
context.watch(watchee)
override def receive: Receive = {
case "start" =>
state = "start"
case _: Terminated =>
state = "terminated"
}
}
test("example") {
val watchee = TestProbe()
val watcher = TestActorRef[WatcherActor](Props(new WatcherActor(watchee.ref)))
assert(watcher.underlyingActor.state === "initial")
watcher ! "start" // "start" will be sent and handled by watcher synchronously
assert(watcher.underlyingActor.state === "start")
system.stop(watchee.ref) // will cause Terminated to be sent and handled asynchronously by watcher
Thread.sleep(100) // what is the best way to avoid blocking here?
assert(watcher.underlyingActor.state === "terminated")
}
}
Now, since all involved actors use CallingThreadDispatcher
(all Akka's test helpers gets constructed using props with .withDispatcher(CallingThreadDispatcher.Id)
) I can safely assume that when this statement returns:
watcher ! "start"
... the "start" message is already processed by WatchingActor
and thus I can make assertions based in the watcher.underlyingActor.state
However, based on my observations, when I stop watchee
using system.stop
or by sending Kill
to it the Terminated
message produced as a side effect of watchee
death gets executed asynchronously, in another thread.
Not-a-solution is to stop watchee
, block thread for some time and verify Watcher
state after that, but I'd like to know how to I do this the right way (i.e. how to be sure that after killing actor it's watcher received and processed Terminated
message signaling it's death)?