1

テストで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() は時間内に作成できないと推測できます。私に何ができる?

4

1 に答える 1

2

これは基本的に、Akka の単体テストで試して回避したい非同期性の問題に要約されます。アクターTestActorRefの に夢中になるCallingThreadDispatcherためにを正しく使用しています。masterしかし、 を呼び出すとsystem.stop(worker)systemデフォルトの非同期ディスパッチャが引き続き使用され、ワー​​カーの停止と再作成時にこの競合状態が発生します。この問題を一貫して修正する最も簡単な方法は、次のようにワーカーを停止することです。

master.underlyingActor.context.stop(worker)

あなたはcontextofを使用してmasterおり、そのアクターCallingThreadDispatcherは 私が試したところ、うまくいきました。

于 2014-10-22T19:46:02.737 に答える