Reputation: 732
Monitoring Akka actors' state is said to be possible by using .underlyingActor.
In the example below, there is an ActorWithState using an Integer counter. The process of counter's incrementation and decrementation is tested by an ActorWithStateTest. The incrementation step always passes. However, counter's decrementation does not seem to work in that the 2nd assert always fails. The error message is the following. What is wrong?
[Error message of this test]
[info] ActorWithStateTest
[info] - should validate counter incrementation and decrementation *** FAILED ***
[info] 1 did not equal 0, Expected counter to be 0 after 'Terminated' message
[Actor with counter]
object ActorWithState {
case class Inc;
}
class ActorWithState(snooper: ActorRef) extends Actor with ActorLogging {
var counter = 0
def receive = {
case Inc => counter += 1
case Terminated(ref) => counter -= 1
}
}
[ActorTest shall test counter's behaviour]
class ActorWithStateTest extends TestKit(ActorSystem("SimpleTestSpec")) {
"Test" should {
"validate counter incrementation and decrementation" in {
val aws = TestActorRef(Props(classOf[ActorWithState], testActor), name = "aws")
val awsA: ActorWithState = aws.underlyingActor
// tell aws to increment its counter
aws ! ActorWithState.Inc
// this assert always passes
assert(awsA.counter == 1, ", Expected counter to be 1 after 'Inc' message")
// triggers a 'Terminated' message being sent to aws
val tp = TestProbe()
aws watch tp.ref
system stop tp.ref
// [EDIT] the following assert passes if some - time consuming - processing is added here
// the following assert does NOT pass, WHY?
assert(awsA.counter == 0, ", Expected counter to be 0 after 'Terminated' message")
}
}
[akka-actor: 2.3.2, akka-testkit: 2.3.2, scalatest: 2.0]
Upvotes: 2
Views: 369
Reputation: 35443
As mentioned in my comment, your issue stems from the stopping of an actor being async. Your assertion is happening before the Terminated
message hits your actor that you are testing. One quick and dirty way to fix this is to introduce another probe that also listens for the terminated event and perform an assertion on that first. That will wait until the terminated is received by the second watcher which should mean that your actor has also received the terminated event and you can perform your assertion. This worked for me:
val tp = TestProbe()
val tp2 = TestProbe()
aws watch tp.ref
tp2 watch tp.ref
system stop tp.ref
tp2.expectTerminated(tp.ref)
assert(awsA.counter == 0, ", Expected counter to be 0 after 'Terminated' message")
Upvotes: 3