BAM Weblog

Using ScalaCheck with Akka and Specs2

Brian McKenna2012-06-17

I spent some time this weekend playing around with Akka. It took me a while to get it to work nicely with ScalaCheck and Specs2.

My first attempt was to make the test create a new Akka TestKit:

def e1 = new TestKit(system) with Scope with ImplicitSender {
  within(1 second) {
    system.actorOf(Props(new Actor {
      def receive = { case x ⇒ sender ! x }
    })) ! "hallo"

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

But I couldn't get ScalaCheck to work inside of the Scope. Instead, I had to move the TestKit up to the Specification class. Then I could make a big trait with everything I needed:

trait AkkaScalaCheck extends
  Specification with
  NoTimeConversions with
  ScalaCheck with
  ImplicitSender { self: TestKit => }

Specs2 will automatically run tests in parallel (awesome feature) but that broke my tests because actors were sending responses to queries from other tests.

I just had to tell Specs2 to run tests sequentially:

testOptions in Test += Tests.Argument("sequential")

I tried just inserting sequential in the Specification but that didn't work for me. I'll try to narrow down why soon.

The final code looks something like this:

import org.specs2.{ Specification, ScalaCheck }
import org.specs2.specification.Step
import org.specs2.time.NoTimeConversions

import akka.actor.{ Props, ActorSystem }
import akka.testkit.{ TestKit, ImplicitSender }
import akka.util.duration._

trait AkkaScalaCheck extends
  Specification with
  NoTimeConversions with
  ScalaCheck with
  ImplicitSender { self: TestKit => }

class MySpec(system: ActorSystem) extends TestKit(system) with AkkaScalaCheck {
  def this() = this(ActorSystem("MySpec"))

  def is =
    "Test should" ^
      p ^
      "pass" ! e1 ^
    Step(system.shutdown()) ^ end

  val ping = system.actorOf(Props[Ping])

  def message[A] = receiveOne(1 second).asInstanceOf[A]

  def e1 = check((a: Int) => {
    ping ! a
    message must be equalTo a
  })
}
Please enable JavaScript to view the comments powered by Disqus.