【问题标题】:Time for create TestProbe in Akka TestKit在 Akka TestKit 中创建 TestProbe 的时间
【发布时间】:2014-10-23 23:11:54
【问题描述】:

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

trait ActorRefFactory {
  this: Actor =>

  def actorOf(props: Props) = context.actorOf(props)
}

我有工人演员,当收到任何消息时会停止自我:

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() 不能及时创建。我能做什么?

【问题讨论】:

  • 如果我发送给工人 PoisonPill 而不是 system.stop(worker),它可以工作。但我不知道为什么。

标签: akka akka-testkit


【解决方案1】:

这基本上归结为您希望在 Akka 的单元测试中尝试避免的异步问题。您正确地使用了TestActorRef 来吸引master 演员的CallingThreadDispatcher。但是当您调用system.stop(worker) 时,system 仍然我们使用默认的异步调度程序,它将在停止然后重新创建工作人员时引入这种竞争条件。我能看到始终如一地解决此问题的最简单方法是像这样停止工作人员:

master.underlyingActor.context.stop(worker)

因为您使用的是mastercontext,而该演员使用的是CallingThreadDispatcher,我相信这将消除您所看到的asnyc 问题。当我尝试它时,它对我有用。

【讨论】:

  • 不幸的是,它不起作用。例如,如果我在 Terminated 的情况下添加 println 语句,我就明白了。这意味着 Master actor 收到了终止的消息。
  • @Leonard,你为什么在停止后重新断言尺寸仍应为 2?如果正确接收到终止,则列表的大小应该从 2 变为 1。您的失败是告诉您您的大小是 1,这与您对 2 的期望不符,但您的期望实际上应该是 1。
  • 没那么简单。查看 createWorker() 方法。当 worker 被终止时,master 创建新的 worker 并将其放入 worker 集中。
  • @Leonard,我添加了另一个答案。当我尝试时,这个对我有用。
猜你喜欢
  • 1970-01-01
  • 2019-12-19
  • 1970-01-01
  • 1970-01-01
  • 2016-10-08
  • 1970-01-01
  • 2020-04-17
  • 2019-12-10
  • 1970-01-01
相关资源
最近更新 更多