Reputation: 6130
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?
Upvotes: 0
Views: 177
Reputation: 40500
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)
Upvotes: 2