Thursday, April 19, 2012

Improved testing messages send by Actor with Akka

Earlier this week I wrote a post about how to test the message send to an actor which is looked up by the actor under test. This week I attended the Scala Days in London and had a chat about this with Roland Kuhn of TypeSafe, who did a presentation about testing Akka. He suggested a better way to test this so TestKit's testActor is used and you can make use of the expected message assertions and 'within' timing options.
The solution he proposed is quite simple actually (why didn't I think of that?): just create a Forwarding Actor which forward all messages to the testActor and register it with the name used by the actor under test.

So here's how the test then looks like:

package testing

import org.scalatest.matchers.ShouldMatchers
import akka.testkit.TestKit
import org.scalatest.{FeatureSpec, BeforeAndAfterAll}
import akka.actor.{ActorRef, Props, ActorSystem, Actor}
import testing.ProperTestASendingMsgToB.{A, ForwardingActor}

object ProperTestASendingMsgToB {

  // The Actor to test
  class A extends Actor {
    val next = context.actorFor("/user/B")

    def receive = {
      case s: String => {
        println("Received by A: %s" format s)
        next ! s
      }
    }
  }

  // A utility Actor which forwards everything to a target actor
  class ForwardingActor(targetActor: ActorRef) extends Actor {
    def receive = {
      case msg => targetActor ! msg
    }
  }
}

class ProperTestASendingMsgToB(system: ActorSystem) extends TestKit(system)
    with FeatureSpec with ShouldMatchers with BeforeAndAfterAll {

  def this() = this(ActorSystem("Test"))

  feature("'A' must send message to 'B'") {
    scenario("Test using TestKit's testActor") {

      import system._
      // register Forwarding Actor with name 'B'. Forward to testActor.
      actorOf(Props(new ForwardingActor(testActor)), "B")
      // create actor to test
      val actorA: ActorRef = actorOf(Props[A])

      import akka.util.duration._
      // validate message received within 100 millis
      within(100 millis) {
        // send the message
        actorA ! "some text"
        // verify message received by testActor
        expectMsg("some text")                   
      }
    }
  }
}

Monday, April 16, 2012

Testing message send by Actor with Akka

Update: Talked to Roland Kuhn at Scala Days in London and he suggested a better way to test this. I created a new blogpost with the new solution.

Last week I've been diving into Akka. Before building my first Akka code, I wanted to know how to properly test Akka applications, so I can do proper TDD. The Akka documentation provides an excellent starting place. It provides some examples of how to test actors and the messages they send, but I noticed that all those test provide the target actor as a constructor argument to the actor-under-test.

I can't image you always want to pass target actors. When using an actor for a boundary, that would mean you have to carry that actor from front to back to pass it to the whole actor hierarchy. I image that's why they made the actor lookup in the first place. But when the actor-under-test does a lookup of it's target actor, how do you test that the target actor receives the correct message? I don't want to create a seperate constructor just for testing.

My first tries to use the testActor of TestKit failed. It's impossible to register the testActor under a custom name for testing. Also trying to use TestProbe and TestActorRef was not successful. You can't construct an instance of a custom actor and use that with TestActorRef.
Finally, after reading through the API, I found that you can create a TestActorRef and pass a custom name with it, just like you create a normal actor. Somehow the TestActorRef cannot find an implicit ActorSystem, even though the test extends TestKit, so an additional implicit assignment of ActorSystem was needed.

So, here's an example of how to test an actor which sends a message to a target actor which it requires via lookup:

package testing

import org.scalatest.matchers.ShouldMatchers
import org.scalatest.{BeforeAndAfterAll, FeatureSpec}
import akka.actor.{Props, ActorSystem, Actor}
import akka.testkit.{TestActorRef, TestKit}

class A extends Actor {
  val next = context.actorFor("/user/B")

  def receive = {
    case s: String => {
      println("Received by A: %s" format s)
      next ! s
    }
  }
}

/**
 * An Actor which captures the message so it can be verified in test.
 */
class CaptureMsgActor extends Actor {
  var capturedMessage = ""
  def receive = {
    case msg => {
      capturedMessage = msg.asInstanceOf[String]
      println("Received by B: %s" format msg)
    }
  }
}

class TestASendingMsgToB(system: ActorSystem) extends TestKit(system)
    with FeatureSpec with ShouldMatchers with BeforeAndAfterAll {

  def this() = this(ActorSystem("Test"))

  feature("'A' must send message to 'B'") {
    scenario("A message send to 'A' must be received by 'B'") {

      // implicit system needed for creating an TestActorRef using Props and name
      implicit val testSystem = this.system
      // create an TestActorRef of type CaptureMsgActor and register under name of "B" (which name is used by actor under test 'A')
      val actorB: TestActorRef[CaptureMsgActor] = TestActorRef(Props[CaptureMsgActor], name = "B")
      // create actor to test. Use TestActorRef so message is send synchronous.
      val actorToTest = TestActorRef[A]
      // send a message to the actor under test
      actorToTest ! "some text"
      // validate message captured
      actorB.underlyingActor.capturedMessage should equal("some text")
    }
  }
}


Getting started with Scala in Java projects

Tips for an optimal interoperability

Last Januari I wrote an article about using Scala in Java projects and the interoperability between Scala and Java. Unfortunately the publisher of the Dutch Java Magazine, in which it was going to be published, went bankrupt in Februari. So to not let my effects go to waist, I'm publishing it on my own site now.

Article intro:
It's been two years since Scala featured in the Dutch Java Magazine. Meanwhile Scala has become a mature language and is gaining more and more followers. Logical because Scala already has the features that are not expected in Java for another 2 or 3 years, if ever. These features not only result in less code,  but also provides better and more readable code. Many Java projects are large and have been around for many years. It is not realistic to expect that such projects will be reimplemented in Scala. That is not necessary, because Scala is very wellinto existing projects.

This article is about how to use Scala in Java projects, use Scala from Java and vise versa, how to use Scala with Maven, SBT, editors, etc. Read the whole article...

(This article was written in Dutch. I'm working on a translation in English.)