Alexander Tokarev
Alexander Tokarev

Reputation: 2763

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

I've designed an actor that should send its' actorRef to another actor on prestart:

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

case class Register(actor: ActorRef)

Then I've written a specification for this 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))
     }
  }
}

When I run my test, it fails with the following message: assertion failed: expected Register(Actor[akka://MyActorSpec/user/$b#1849780829]), found Register(Actor[akka://MyActorSpec/user/$a#1143150267])

So, it seems that ActorRef obtained via self inside MyActor is not equal to ActorRef obtained via system.actorOf in my test. Any suggestions?

Upvotes: 2

Views: 242

Answers (3)

Alexander Tokarev
Alexander Tokarev

Reputation: 2763

I've figured it out. It was because I've used shared TestProbe in several test cases, in which I create different instances of 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))
         ....
     }
  }
}

Instead, using a fresh instance of TestProbe for each test case helped.

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))
         ....
     }
  }
}

Anyway, thanks to all for proving that for single test case it works well.

Upvotes: 0

Jatin
Jatin

Reputation: 31724

The code you posted ideally should not even compile at:

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

Because the constructor expects an ActorRef which we are not passing. But correcting it, it works:

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))
    }
  }
}

For a second, just to make sure that there is no special magic happening because of ActorProbe, I wrote plain old actor class below.

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()
  }
}

And it prints true. So there is nothing wrong with your programme.

Upvotes: 1

alekseevi15
alekseevi15

Reputation: 1782

The following code is working just fine for me (the test passes):

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))
    }
  }
}

Upvotes: 1

Related Questions