在 akka.testkit.TestKit 中测试消息转发
Testing message forwarding in akka.testkit.TestKit
我想测试以下场景:
假设我有一个 parent 演员,它创建了两个这样的 child 演员。
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")
}
}
}
我想测试如果 parent 得到 'ping'
他会发送 'ping forwarded'
消息给自己的 children。
是否可以用 TestKit 做到这一点?
大概是这样的吧?
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")
就个人而言,只要有可能,我更喜欢 "traditional" 方法:
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"
}
}
现在,您可以运行直接进行测试:
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)
我想测试以下场景:
假设我有一个 parent 演员,它创建了两个这样的 child 演员。
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")
}
}
}
我想测试如果 parent 得到 'ping'
他会发送 'ping forwarded'
消息给自己的 children。
是否可以用 TestKit 做到这一点?
大概是这样的吧?
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")
就个人而言,只要有可能,我更喜欢 "traditional" 方法:
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"
}
}
现在,您可以运行直接进行测试:
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)