John Mullins
John Mullins

Reputation: 1101

Testing delayed messages with the help of akka-testkit

There are two actors - ProducerActor and ConsumerActor. Producer has a scheduler which sends "Tick" message to itself each 2000 ms. After that the producer sends "Hello" message to consumer:

class ProducerActor(consumer: ActorRef) extends Actor {
    override def receive: Receive = {
      case "Tick" =>
          ...
          // some code which takes < 1 ms
          ...
          consumer ! "Hello"
    }

    override def preStart: Unit = 
      context.system
         .scheduler
         .schedule(2000 milliseconds, 2000 milliseconds, self, "Tick")
}

Is it possible to test the case when the consumer actor receives a "Hello" message each 2000 ms? So, if message is received in period < 2000 ms or > 2000 ms then test will assert error.

For example:

"Consumer test" should {
    "receive message each 2000 ms" in {
       ...
       val consumer = TestProbe()
       val producer = system.actorOf(Props(new ProducerActor(consumer.ref))
       ...
       consumer.howToExpectDelayedMessage(minDelay = 2000 millis, "Hello")

    }
}

--- UPD ---

I have figured out the following solution which works fine for me:

"Consumer test" should {
    "receive message each 2000 ms" in {

       val consumer = TestProbe()
       val producer = system.actorOf(Props(new ProducerActor(consumer.ref))

       // check the first ten periods
       (0 to 10) foreach { _ =>
         consumer.expectNoMsg(2000 millis)
         consumer.expectMsg("Hello")
       }

    }
}

But if there is a better solution for this task it would be great if you could share.

Upvotes: 0

Views: 714

Answers (1)

allema_s
allema_s

Reputation: 151

You can use Timing Assessions to do that.

certain events must not happen immediately (like a timer), others need to happen before a deadline. Therefore, all examination methods accept an upper time limit within the positive or negative result must be obtained.

import akka.actor.Props
import scala.concurrent.duration._

val worker = system.actorOf(Props[Worker]())
within(200 millis) {
  worker ! "some work"
  expectMsg("some result")
  expectNoMessage() // will block for the rest of the 200ms
  Thread.sleep(300) // will NOT make this block fail
}

The block given to within must complete after a duration which is between min and max, where the former defaults to zero.

Upvotes: 1

Related Questions