5

I have the following Subscriber abstract base class:

abstract class Subscriber(topics: Seq[String]) extends Actor with ActorLogging {
  import DistributedPubSubMediator.{ Subscribe, SubscribeAck }

  val mediator = DistributedPubSub(context.system).mediator

  // subscribe to each topic
  topics.foreach{mediator ! Subscribe(_, self)}

  def receive = {
    case SubscribeAck(Subscribe(name, None, `self`)) ⇒
      log.info(s"Subscribing to $name")
  }
}

And I'd like to test that it receives messages that are published to topics to which a subclass is subscribed. Some simple pseudocode that demonstrates that is the following:

val topic = "foo"

class FooSubscriber extends Subscriber(Seq(topic))

val fooSubActor = system.actorOf(Props[FooSubscriber])    
val mediator = DistributedPubSub(system).mediator
val msg = "This is a string"

// Publish the msg to the "foo" topic.
mediator ! Publish(topic, msg)

fooSubActor.expectMsg(msg)

The only way I know to make assertions about messages that specific actors receive is by way of TestProbe, but I don't know how I could make a TestProbe extend my class.

Typically the Akka docs have loads of sample code with associated test suites, but I couldn't find anything in the Akka Cluster docs related to testing the receive method.

Does anyone have suggestions?

erip
  • 16,374
  • 11
  • 66
  • 121
  • A kludge is to override `receive` and change a member variable when the actor receives anything and make an assertion that the member variable is set in my test... but this is bad. Looking for a more idiomatic testing approach. – erip Jan 04 '17 at 12:31

1 Answers1

0

This is a textbook example of where Dependency Injection helps with testability.

If you receive the mediator for DistPubSub in the Subscriber constructor instead of directly asking for it you can just test the Suscriber actor in isolation, without the need to use the DistPubSub as part of your test fixture.

emilianogc
  • 880
  • 4
  • 19
  • The mediator isn't the problem -- the issue is the expectation of receiving a message in the subscriber. – erip Jan 04 '17 at 20:19
  • 1
    But in that case you are only really testing the PubSub extension and not the logic of your actor – emilianogc Jan 05 '17 at 11:45
  • Not true. Perhaps you don't understand my question -- I'm trying to test the logic of my actor. The mediator is independent the subscriber, which is why you would use a `PubSub` in the first place -- to obviate keeping track of who is publishing necessarily. – erip Jan 05 '17 at 11:51
  • 1
    In the example you are providing the only logic present for your Subscriber actor is subscribing to specific topics and logging when an Ack is received. In the example test you assert that the subscriber receives a message after publication to the PubSub system. But that is not a responsibility of the Suscriber, only of the PubSub, thus you are only really asserting that the PubSub resends messages. On the other hand, what is a responsibility of the Suscriber is to subscribe to the topics, so if you send a TestProbe for mediator you can assert that it actually sends the Subscribe messages – emilianogc Jan 05 '17 at 16:37