4

I have searched a lot about this and yet have no answer.

I have a Actor "A" (user/A) that send message "X" for a other actor "B" (user/B) when receive a message "M". To do this the actor A use ActorSelection I need test that when I send M to A, B will receive "X".

I try do this using TestProbe on "user/B" but have not success.

I also see some similar questions about this but every answer said to use ActorRef insted of ActorSelection. This is not a option for me, I realy need use a ActorSelection.

Someone have some idea ?

Rafael Pacheco
  • 472
  • 1
  • 5
  • 15
  • Why do you need to use `ActorSelection`? – Ryan Sep 13 '15 at 16:39
  • 1
    In my case I have a lot of actors on path "/user/agents/*", but these actors are volatiI and I have not "ActorRef" for all actors. On the other hand I have one actor "/user/xpto" that send message "X" for "/user/agents/*" always receive a message "M". I dont understand why is so complicated mock some actor on akka system. – Rafael Pacheco Sep 13 '15 at 18:30

2 Answers2

6

Simple answer: instead of hard-coding the selection’s path in A make that configurable. In the test you can then point that to the path of a TestProbe.

Roland Kuhn
  • 15,412
  • 2
  • 36
  • 45
  • It may be worth noting that this is harder to do in the current Release version of Akka since TestProbe names can't be controlled (http://doc.akka.io/api/akka/2.3.14/index.html#akka.testkit.TestProbe$) But in the latest Release candidate there is a new `apply` method to set the name: http://doc.akka.io/api/akka/2.4.0-RC2/index.html#akka.testkit.TestProbe$ – mattinbits Sep 17 '15 at 08:57
  • 2
    You don't need to control the name since you can obtain it from `probe.ref.path`. – Roland Kuhn Sep 17 '15 at 12:50
5

You can write simple helpers for your tests that are named like your actors but forward messages to your probes.

Assuming that this is your setup (simplified):

case object M
case object X
class A extends Actor {
  def receive = {
    case M => context.system.actorSelection("/user/B") ! X
  }
}

You want to test actor A.

You can write this kind of "test framework" for your app:

object ForwardActor {
  def props(to: ActorRef) = Props(new ForwardActor(to))
}

class ForwardActor(to: ActorRef) extends Actor {
  override def receive = {
    case x => to forward x
  }
}

def mock(name: String, probe: TestProbe)(implicit system: ActorSystem): Unit = 
  system.actorOf(ForwardActor.props(probe.ref), name)

Then you will be able to test actor A by simply doing this kind of test:

"A sends X to B after receiving M" in {
  val probeB = TestProbe()
  mock("B", probeB)
  system.actorOf(Props(new A)) ! M
  probeB expectMsg X
}
Michał Płachta
  • 687
  • 6
  • 12