在Akka TestKit中创建TestProbe的时间

在Akka TestKit中创建TestProbe的时间,akka,akka-testkit,Akka,Akka Testkit,我在测试中具有覆盖actorOf的特性: trait ActorRefFactory { this: Actor => def actorOf(props: Props) = context.actorOf(props) } 我还有worker actor,当收到任何消息时,它会停止self: class WorkerActor extends Actor { override def receive: Actor.Receive = { case _ =>

我在测试中具有覆盖actorOf的特性:

trait ActorRefFactory {
  this: Actor =>

  def actorOf(props: Props) = context.actorOf(props)
}
我还有worker actor,当收到任何消息时,它会停止self:

class WorkerActor extends Actor {
  override def receive: Actor.Receive = {
    case _ => { context.stop(self) }
  }
}
我还有一个主演员,他创建演员并让他们排队:

class MasterActor extends Actor with ActorRefFactory {
  var workers = Set.empty[ActorRef]

  override val supervisorStrategy = SupervisorStrategy.stoppingStrategy

  def createWorker() = {
    val worker = context watch actorOf(Props(classOf[WorkerActor]))
    workers += worker
    worker
  }

  override def receive: Receive = {
    case m: String =>
      createWorker()
    case Terminated(ref) =>
      workers -= ref
      createWorker()
  }
}
这项测试失败了:

class ActorTest(val _system: ActorSystem) extends akka.testkit.TestKit(_system)
  with ImplicitSender
  with Matchers
  with FlatSpecLike {

  def this() = this(ActorSystem("test"))

  def fixture = new {
    val master = TestActorRef(new MasterActor() {
      override def actorOf(props: Props) = TestProbe().ref
    })
  }

  it should "NOT FAILED" in {
    val f = fixture

    f.master ! "create"
    f.master ! "create"

    f.master.underlyingActor.workers.size shouldBe 2

    val worker = f.master.underlyingActor.workers.head
    system.stop(worker)
    Thread.sleep(100)

    f.master.underlyingActor.workers.size shouldBe 2
  }

}

在测试中Thread.sleep之后,我给出了错误“1不等于2”。我不知道发生了什么事。但是,如果我猜的话,我可以假设TestProbe()不能及时创建。我能做什么呢?

这基本上归结为一个异步性问题,您希望在Akka的单元测试中尝试并避免这个问题。您正确地使用了
TestActorRef
连接到
master
参与者的
callingreaddispatcher
。但是当您调用
system.stop(worker)
时,
系统仍然使用默认的异步调度程序,它将在停止并重新创建worker时引入此竞争条件。我所能看到的一致解决此问题的最简单方法是阻止工人这样做:

master.underlyingActor.context.stop(worker)

因为您正在使用
master
context
,而该参与者正在使用
callingReadDispatcher
我相信这将消除您看到的asnyc问题。当我尝试它时,它对我有效

不幸的是,它不起作用。例如,如果我在case-Terminated中添加println语句,我就得到了它。这意味着主演员收到了终止消息。@Leonard,为什么你在停止后再次断言大小仍应为2?如果正确接收到终止列表,则列表的大小应从2变为1。你的失败告诉你你的尺寸是1,这与你期望的2不符,但你的期望值实际上应该是1。这并不是那么简单。请看createWorker()方法。当工人被终止时,请创建新工人并将其放入工人集中。@Leonard,我添加了另一个答案。这一个在我尝试它时对我有效。如果我将毒药发送给工人而不是系统。停止(工人),它有效。但我不知道为什么。