Create TestProbe of an child actor from a name

198 views Asked by At

Using akka typed: 2.6.10. My parent generates child actors to do some work as you can see below (note this is part of event sourced actor). Is there a way to acquire reference to internally created child actor using possibly name during testing time?

For example, below we have child actor provider_1 which is created at initialization time and I am hoping to acquire a reference to TestProbe using this name from outside. I am reluctant to change the way code is structured for sake of testing, for example in here there are some reference to passing in ref/factory or re-constructing parent in test in order to test this, which I would like to avoid.

  def commandHandler(
    ctx: ActorContext[Command]
  ): (State, Command) => Effect[Event, State] = { (state, cmd) =>
    cmd match {
      case Init =>
         ctx.spawn(Provider(ctx.self), "provider_1")
        Effect.none
    }
  }
1

There are 1 answers

0
Levi Ramsey On

If you're using the BehaviorTestKit to test the actor, the actor gets run with an alternative ActorContext implementation.

So the following should work (note that akka.actor.testkit.typed.Effect has little relation to Effect in persistence), using scalatest matchers:

import akka.actor.testkit.typed.Effect.Spawned

val testKit = BehaviorTestKit(behaviorUnderTest)
testKit.run(Init)
val effect = testKit.retrieveEffect : akka.actor.testkit.typed.Effect
val childActorRef =
  effect match {
    case s: Spawned if s.childName == "provider_1" => s.ref
    case _ => fail()
  }
val childInbox = testKit.childInbox(childActorRef)
testKit.run(SendMessageToYourChild("hello"))
childInbox.hasMessages shouldBe true
childInbox.receiveMessage shouldBe MessageFromParent("hello")

akka.actor.testkit.typed.scaladsl.TestInbox is intended to be the synchronous behavior testing analogue to the asynchronous TestProbe.

I'm not aware of an analogous method for the asynchronous ActorTestKit, where a child actor will actually be spawned.