This year I have been working on several systems based on Akka, usually in combination with the excellent Spray framework to build fully asynchronous actor-driven REST servers. All in all this has been going very well but recently I had to reinvent a certain wheel for the third time (on the third project) so I thought it might be good to blog about it so others can benefit from it too.

The problem is very simple: Akka has great unit test support but unfortunately (for me) that support is based on ScalaTest. Now there is nothing wrong with ScalaTest but personally I prefer to write my tests using Specs2 and it turns out that mixing Akka TestKit with Specs2 is a little tricky. The Akka documentation does mention these problems and it gives a brief overview of ways to work around them, but I could not find any current example code online.

I say "current" because one of Akka's main committers, Roland Kuhn, did at one time commit some specs2 example code but unfortunately it got thrown out again later.

Based on that original example, here is my slightly improved and commented version:

import org.specs2.mutable._
import org.specs2.time.NoTimeConversions

import akka.actor._
import akka.testkit._
import akka.util.duration._

/* A tiny class that can be used as a Specs2 'context'. */
abstract class AkkaTestkitSpecs2Support extends TestKit(ActorSystem()) 
                                           with After 
                                           with ImplicitSender {
  // make sure we shut down the actor system after all tests have run
  def after = system.shutdown()
}

/* Both Akka and Specs2 add implicit conversions for adding time-related
   methods to Int. Mix in the Specs2 NoTimeConversions trait to avoid a clash. */
class ExampleSpec extends Specification with NoTimeConversions {
  sequential // forces all tests to be run sequentially

  "A TestKit" should {
    /* for every case where you would normally use "in", use 
       "in new AkkaTestkitSpecs2Support" to create a new 'context'. */
    "work properly with Specs2 unit tests" in new AkkaTestkitSpecs2Support {
        within(1 second) {
          system.actorOf(Props(new Actor {
            def receive = { case x ⇒ sender ! x }
          })) ! "hallo"

          expectMsgType[String] must be equalTo "hallo"
        }
      }
  }
}

Using this little Specs2 context trick bridges the two systems, allowing you to write normal Akka TestKit-based tests but using Specs2 as the test driver and matcher library.