I want to test the following scenario:
Assume I have a parent actor, which creates two child actors like this.
class A extends Actor {
def getActorOf(props: Props) = {
context.actorOf(props, props.clazz.getTypeName)
}
def receive: Receive = {
case "ping" => {
val bChild = getActorOf(Props[B])
val cChild = getActorOf(Props[C])
Seq(bChild, cChild)
.foreach(child => child ! "ping forwarded")
}
}
}
I want to test that if in case the parent get 'ping'
he will send 'ping forwarded'
message to both own children.
Is it possible to do this with TestKit?
Something like this, perhaps?
class TestMe extends A {
val (probeB, probeC) = (TestProbe(), TestProbe())
override def getActorOf(props: Props) = props match {
case Props(_, classOf[B], _) => probeB.ref
case Props(_, classOf[C], _) => probeC.ref
}
}
val fixture = TestActorRef[TestMe](Props[TestMe])
fixture ! "ping"
fixture.underlyingActor.probeB.expectMsg("ping forwarded")
fixture.underlyingActor.probeB.expectMsg("ping forwarded")
Personally, I prefer a more "traditional" approach, whenever possible:
trait Forwarder {
def startAndForward[T : ClassTag](message: Any)(implicit context: ActorContext) = {
val actor = context.actorOf(Props[T])
actor ! message
actor
}
}
object Forwarder extends Forwarder
class A(f: Forwarder = Forwarder) extends Actor {
def receive: Receive = {
case m@"ping" =>
f.startAndForward[B]("ping forwarded")
f.startAndForward[C]("ping forwarded")
sender ! "pong"
}
}
Now, you can run your test in straightforward way:
val fwd = mock[Forwarder]
val fixture = context.actorOf(Props(new A(fwd)))
fixture.ask("ping").futureValue shouldBe "pong"
verify(fwd).startAndForward[B](ArgumentMatchers.eq("ping forwarded"))(any, any)
verify(fwd).startAndForward[C](ArgumentMatchers.eq("ping forwarded"))(any, any)