通过 system.actorOf 获得的 ActorRef 是否等于这个 actor 中的 self?

Does ActorRef obtained via system.actorOf equal to self inside this actor?

我设计了一个 actor,它应该在启动前将它的 actorRef 发送给另一个 actor:

class MyActor(notifier: ActorRef) extends Actor {
  override def preStart(): Unit = {
    notifier ! Register(self)
  }
  ...
}

case class Register(actor: ActorRef)

然后我为这个 Actor 写了一个规范:

class MyActorSpec extends TestKit(ActorSystem("MyActorSpec"))
                  with ImplicitSender 
                  with WordSpecLike 
                  with Matchers 
                  with BeforeAndAfterAll {

  "MyActor" should {
     val notifier = TestProbe()
     "register itself in notifier" in {
         val myActor = system.actorOf(Props(classOf[MyActor], notifier.ref))
         notifier.expectMsg(Register(myActor))
     }
  }
}

当我 运行 我的测试时,它失败并显示以下消息:assertion failed: expected Register(Actor[akka://MyActorSpec/user/$b#1849780829]), found Register(Actor[akka://MyActorSpec/user/$a#1143150267])

因此,在我的测试中,MyActor 中通过 self 获得的 ActorRef 似乎不等于通过 system.actorOf 获得的 ActorRef。有什么建议吗?

以下代码对我来说工作正常(测试通过):

class MyActor(notifier: ActorRef) extends Actor {
  override def preStart(): Unit = {
    notifier ! Register(self)
  }

  override def receive: Receive = {
    case _ =>
  }
}

case class Register(actor: ActorRef)

class MyActorSpec extends TestKit(ActorSystem("MyActorSpec")) with ImplicitSender with WordSpecLike with Matchers with BeforeAndAfterAll {
  "MyActor" should {
    val notifier = TestProbe()
    "register itself in notifier" in {
      val myActor = system.actorOf(Props(new MyActor(notifier.ref)))
      notifier.expectMsg(Register(myActor))
    }
  }
}

理想情况下,您发布的代码甚至不应在以下位置编译:

val myActor = system.actorOf(Props(classOf[MyActor], notifier))

因为构造函数需要一个我们没有传递的 ActorRef。但是纠正它,它有效:

class MyActorSpec extends TestKit(ActorSystem("MyActorSpec"))
with ImplicitSender
with WordSpecLike
with Matchers
with BeforeAndAfterAll {

  "MyActor" should {
    val notifier = TestProbe()
    "register itself in notifier" in {
      val myActor = system.actorOf(Props(classOf[MyActor], notifier.ref))
      notifier.expectMsg(Register(myActor))
    }
  }
}

暂时,为了确保没有因为 ActorProbe 而发生特殊的魔法,我在下面写了普通老演员 class。

object Prac {
  def main(args: Array[String]) {
    val system = ActorSystem("HelloSystem")
    val myActor = system.actorOf(Props(classOf[MainActor]))
  }

}

class MyActor(notifier: ActorRef) extends Actor {

  override def preStart(): Unit = {
    notifier ! Register(self)
  }

  override def receive: Receive = {
    case x => println("My Actor ->"+x)
  }
}

case class Register(actor: ActorRef)

class MainActor extends Actor{

  val actor = context.actorOf(Props(classOf[MyActor], self))

  override def receive = {
    case Register(x) =>
      println(actor == x)
      context.system.shutdown()
  }
}

并打印 true。所以你的程序没有问题。

我已经弄明白了。这是因为我在多个测试用例中使用了共享的 TestProbe,在这些用例中我创建了不同的 MyActor 实例。

class MyActorSpec extends TestKit(ActorSystem("MyActorSpec"))
                  with ImplicitSender 
                  with WordSpecLike 
                  with Matchers 
                  with BeforeAndAfterAll {

  "MyActor" should {
     val notifier = TestProbe()
     "register itself in notifier" in {
         val myActor = system.actorOf(Props(classOf[MyActor], notifier.ref))
         notifier.expectMsg(Register(myActor))
     }
     "do some useful work" in {
         val myActor = system.actorOf(Props(classOf[MyActor], notifier.ref))
         ....
     }
  }
}

相反,为每个测试用例使用新的 TestProbe 实例会有所帮助。

class MyActorSpec extends TestKit(ActorSystem("MyActorSpec"))
                  with ImplicitSender 
                  with WordSpecLike 
                  with Matchers 
                  with BeforeAndAfterAll {

  "MyActor" should {
     "register itself in notifier" in {
         val notifier = TestProbe()
         val myActor = system.actorOf(Props(classOf[MyActor], notifier.ref))
         notifier.expectMsg(Register(myActor))
     }
     "do some useful work" in {
         val notifier = TestProbe()
         val myActor = system.actorOf(Props(classOf[MyActor], notifier.ref))
         ....
     }
  }
}

无论如何,感谢所有人证明它对于单个测试用例运行良好。