我在测试中有覆盖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()无法在时间内创建。我该怎么办?
答案 0 :(得分:2)
这基本上归结为你想在Akka的单元测试中试图避免的异步性问题。您正确使用TestActorRef
来加入CallingThreadDispatcher
演员的master
。但是当你调用system.stop(worker)
时,system
仍然使用默认的异步调度程序,它会在停止然后重新创建一个worker时引入这种竞争条件。我能够始终如一地找到解决这个问题的最简单方法就是像这样阻止工人:
master.underlyingActor.context.stop(worker)
因为您正在使用context
master
并且该演员正在使用CallingThreadDispatcher
我相信这会删除您所看到的asnyc问题。当我尝试它时,它对我有用。