Testing Akka: actors, dependency injection and mocks

I’ve been digging into what the expected way is to test my small Akka system, as described in my previous post on the subject. I think my problem partially arises from being unclear as to the proper mode of dependency injection in Akka. In other words, I don’t know what the proper way is for my Root actor to obtain a reference to its Database and HTTP sub-actors. Does it create them itself? Look them up from a service locator? And what if I need to inject mock actors into the system in some parts in order to test it?

Various bits of Akka documentation suggest different approaches to wiring actors together; for instance, this page in the official docs suggests either passing dependent actors as constructor arguments, creating them in a preStart() method, or passing them to their referring actors in a message and using become() to switch between initialization states. This example from the testkit docs takes the latter approach, but I can’t say I like the result:

class MyDoubleEcho extends Actor {
  var dest1: ActorRef = _
  var dest2: ActorRef = _
  def receive = {
    case (d1: ActorRef, d2: ActorRef) =>
      dest1 = d1
      dest2 = d2
    case x =>
      dest1 ! x
      dest2 ! x
  }
}
/* ... */

val probe1 = TestProbe()
val probe2 = TestProbe()
val actor = system.actorOf(Props[MyDoubleEcho])
actor ! (probe1.ref, probe2.ref)
actor ! "hello"
probe1.expectMsg(500 millis, "hello")
probe2.expectMsg(500 millis, "hello")

This does seem to work, but it seems to me that it pollutes the actor with a bunch of test-related code that probably doesn’t belong in production (by which I mean the receive pattern which takes the two dest parameters).

I have found an interesting take on this question in this presentation by Roland Kuhn, introducing akka-testkit from Scala Days 2012—the entire presentation is worth watching, but the part I’m interested in starts at around 22:05 or so.  After a not terribly helpful note about how if you have difficulty injecting mocks into your code, then there is probably something wrong with your design (there may be something to that, but it’s not all that helpful to hear when you’re looking for a solution for injection), Mr. Kuhn mentions a third option for users of the (then-new) Akka 2.0: actors can use actor path naming to look up their dependent actors; the test ActorSystem can then supplant the real implementations with mocks at the same locations.

Of course, all of this sort of assumes that you have a way of separating out actor creation and lifecycle control from dependency injection itself. A lot of the other Akka literature I’ve read seems to posit the integrated lifecycle management bits of Akka as a feature, right down to the “Let It Crash” maxim on the public Akka blog, and all of these features seem to be in direct opposition to the inversion of control notions that most dependency injection systems are founded on. In the last part of Mr. Kuhn’s talk above, he suggests breaking up actor models into somewhat discrete trees, which then use service locators or similar things to find one another; this might be something I can look into.

There was also a talk at this year’s Scala Days about integrating Spring and Akka, which might have some merit for this purpose, and I recently ran across this promising post which describes an approach to autowiring actors with Spring and Akka 2.2 (in Java). Overall, though, this doesn’t seem to be a problem with a clear solution.

Advertisements
Previous Post
Leave a comment

7 Comments

  1. The tutorials in the Typesafe Activator show both the use of Spring and Cake pattern (which works very nice) for injecting actors with dependencies to DB, etc. However it’s not clear how dependencies to other actors should be handled. I’m working with a modified version of Cake pattern for that but I’m not convinced it’s the best way. I’m wondering if you made any progress in finding a proper solution.

    Reply
    • Hi Christian…

      I haven’t found a perfect solution yet, but I have seen a few more approaches which I’ll probably write about soon. One approach involves separating out the sort of “business logic” inside actors into their own traits; the traits can then be mixed in to regular non-actor classes and tested that way. (This doesn’t seem too satisfactory to me since the idea behind Akka seems to be to write your business logic as a network of actors.)

      I just bought a copy of Akka Concurrency, and it has a section on testing actors which looks very promising. I’ll check out the activator as well, thanks for the pointer to that.

      Reply
  2. “and all of these features seem to be in direct opposition to the inversion of control notions that most dependency injection systems are founded on. ”

    +1. Yes. Exactly

    Reply
  3. It is the nature of actor systems with a supervisory failure recovery nature that object instances will come and go, so the old world of singleton-scoped services becomes less relevant. Actors have to be responsible for the lifecycle of their children. This is not a joining of concerns: object lifecycle and business logic. For many actors, the lifecycle of their children IS their business logic. In this context, we cannot inject instances anymore.

    But, we can inject factories, which is almost as good. Spring has had the capacity to act as a factory all along via the “prototype” scope. So, all you have to do is pass in factories into your actors that get the prototype bean from the app context, and use them in your preStart() methods. What’s more, Spring will inject any non-actor Spring beans into your Spring actors, so you can still leverage legacy services as you transition. You still have to worry about legacy services with a blocking nature, but that’s another story…

    Reply
  1. More on Akka and dependency injection | Tim Gilbert's Blog
  2. Akka and dependency injection: Child actors | prose :: and :: conz
  3. Akka and dependency injection: Child actors | prose :: and :: conz by joescii

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: