Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assert order of messages received using Akka TestProbe

We have an actor that we are writing unit tests for, and as part of the tests we want to assert that certain messages are sent to another actor in a certain order. In our unit tests, the actor receiving the messages is represented by an Akka TestProbe, which gets injected into the actor under test when it is created.

It is no problem to assert that the messages were sent to the test probe, however we have been struggling to work out a way to assert they are sent in the correct order (we could not find any suitable methods for doing this in the documentation). Any ideas how we achieve this?

Below is a minimal implementation that highlights the problem.

Implementation

case class Message(message: String)
case class ForwardedMessage(message: String)

class ForwardingActor(forwardTo: ActorRef) extends Actor {
  def receive = {
    case Message(message) =>
      forwardTo ! ForwardedMessage(message)
  }
}

Unit Test

class ForwardMessagesInOrderTest extends TestKit(ActorSystem("testSystem"))
                                 with WordSpecLike
                                 with MustMatchers {

  "A forwarding actor" must {
    val forwardingReceiver = TestProbe()
    val forwardingActor = system.actorOf(Props(new ForwardingActor(forwardingReceiver.ref)))

    "forward messages in the order they are received" in {
      forwardingActor ! Message("First message")
      forwardingActor ! Message("Second message")

      // This is the closest way we have found of achieving what we are looking for, it asserts
      // that both messages were received, but doesn't assert correct order. The test will pass
      // regardless which way round we put the messages below.
      forwardingReceiver.expectMsgAllOf(
          ForwardedMessage("Second message"),
          ForwardedMessage("First message"))
    }
  }
}
like image 468
robjohncox Avatar asked Feb 13 '23 06:02

robjohncox


1 Answers

I'm going to suggest two changes to your test spec. First, when creating the actor under test, use a TestActorRef like so:

val forwardingActor = TestActorRef(new ForwardingActor(forwardingReceiver.ref))

Using a TestActorRef will assure that the CallingThreadDispatcher is used, removing any complications from testing async code (which an actor is). Once you do that, you can change your assertions to:

forwardingReceiver.expectMsg(ForwardedMessage("First message"))
forwardingReceiver.expectMsg(ForwardedMessage("Second message"))

These assertions are inherently In-Order, so if things came in out of this order, they will fail. This should fix your issues.

like image 149
cmbaxter Avatar answered Feb 20 '23 04:02

cmbaxter