我想测试演员A在收到消息后向演员B发送消息。
我正在玩Play! 2.5我使用工厂,因为我需要在演员内部注入一些类和wSClient之类的东西。
演员A看起来像:
object ActorA {
trait Factory {
def apply(ec: ExecutionContext, actorBRef: ActorRef): Actor
}
}
class ActorA @Inject()(implicit val ec: ExecutionContext,
@Named("actor-b") actorBRef: ActorRef)
extends Actor with ActorLogging with InjectedActorSupport {
override def receive: Receive = {
case i: Long =>
log info s"received $i"
actorBRef ! (i+1)
}
演员B更简单:
object ActorB {
trait Factory {
def apply(): Actor
}
}
class ActorB extends Actor with ActorLogging {
override def receive: Receive = {
case _ =>
log error "B received an unhandled message"
}
}
但是我的测试没有通过,据说预期的消息没有到达,我在测试中得到了一个超时(但它被演员B记录得很好)所以问题来自于测试(和可能是探测器。)
以下是测试:
val actorBProbe = TestProbe()
lazy val appBuilder = new GuiceApplicationBuilder().in(Mode.Test)
lazy val injector = appBuilder.injector()
lazy val factory = injector.instanceOf[ActorA.Factory]
lazy val ec = scala.concurrent.ExecutionContext.Implicits.global
lazy val factoryProps = Props(factory(ec, actorBProbe.ref))
val ActorARef = TestActorRef[ActorA](factoryProps)
"Actor B" must {
"received a message from actor A" in {
ActorARef ! 5L
actorBProbe.expectMsg(6L)
}
}
我还创建了一个最小游戏!应用上面的代码here。
答案 0 :(得分:1)
在你的测试中,actorBProbe
不是传递给ActorA构造函数(ref ActorARef
)的ActorB ref。真正发生的是Guice创建了一个不同的ActorB(名为actor-b
),并将其ref传递给ActorA(ref ActorARef
)构造函数。
测试结束时,ActorB actor-b
接收6L
(如日志中所示)。虽然actorBProbe
没有收到任何结果。
混淆真的来自Guice lifecyle和Actors。根据我的经验,它会产生比我能承受的更多的痛苦。
要证明,只需打印ActorRef的哈希码,您就会发现它们不同。说明如下:
val actorBProbe = TestProbe()
println("actorBProbe with ref hash: " + actorBProbe.ref.hashCode())
和
class ActorA ... {
override def preStart =
log error "preStart actorBRef: " + actorBRef.hashCode()
// ...
}
事实上,在ActorA中,即使ec
与测试代码中的ec
不同。
以下是一种强迫"通过测试,同时证明{}未真正被actorBProbe
使用。
而不是依靠Guice来"连接"演员B,我们告诉Guice将@Named("actor-b")
替换为@Assisted
,就像这样,
import ...
import com.google.inject.assistedinject.Assisted
class ActorA @Inject()(...
/*@Named("actor-b")*/ @Assisted actorBRef: ActorRef)
...
重新进行测试,它会通过。但这可能不是你想要的开始。