JoeMjr2
JoeMjr2

Reputation: 3944

Akka Typed - How to sent Terminated message to BehaviorTestKit

I'm trying to unit test my actor's handling of a "Terminated" message for a child actor. The code under test is something like this:

    case Terminated(terminatedActor) =>
      val actorName = terminatedActor.path.name
      if (actorName.startsWith("ChildActor")) {
        doSomething()
      }
      Behaviors.same

In my unit test, I'm trying to do something like this:

    val testInbox = TestInbox[ParentActor.Request](name = "ChildActor1")
    val testKit = BehaviorTestKit(ParentActor())
    testKit.run(Terminated(testInbox.ref))
    assert( *** that doSomething() happened *** )

The unit test code doesn't compile. I get this error in the call to testKit.run():

type mismatch; found : akka.actor.typed.Terminated required: ParentActor.Request

I assume that this is because the Terminated message does not inherit from my ParentActor.Request trait.

Based on a below comment, I changed the unit test to:

    val testInbox = TestInbox[ParentActor.Request](name = "ChildActor1")
    val testKit = BehaviorTestKit(ParentActor())
    testKit.signal(Terminated(testInbox.ref))
    assert( *** that doSomething() happened *** )

This now compiles, but the call to testKit.signal() now throws a DeathPactException, which the docs say means that the actor is not handling the Terminated message, even though my production code definitely does handle it.

Any idea what is wrong?

Upvotes: 0

Views: 368

Answers (1)

Levi Ramsey
Levi Ramsey

Reputation: 20541

Are you sure that your production code definitely handles the Terminated signal?

Signals are not, from the perspective of a typed Behavior, messages. They are processed by the signal handler installed by receiveSignal. That signal handler takes not just the signal but the ActorContext as well, wrapped up in a tuple. If the response to a Terminated signal doesn't require the context, you still have to match against it:

// inside a .receiveSignal...
case (_, Terminated(terminatedActor)) =>
  val actorName = terminatedActor.path.name
  if (actorName.startsWith("ChildActor")) {
    doSomething()
  }
  Behaviors.same

Note that Akka's test suite includes this test which exercises handling the Terminated signal when sent via testKit.signal:

      val other = TestInbox[String]()
      val testkit = BehaviorTestKit[Parent.Command](Parent.init)
      noException should be thrownBy {
        testkit.signal(Terminated(other.ref))
      }

Upvotes: 2

Related Questions