Wednesday, September 1, 2010

Adding Scala unit tests

In my previous post, I showed how the Producer worked by adding some example code to my Simulation object. This might be very suitable for small projects, but in the long run I always prefer to have unit tests. In this post I will show how I added Scala unit tests to my project.

Choosing a framework

After playing around with some different frameworks, I have decided to go for Scala Specs. The syntax of Scala Specs is interesting enough to enjoy writing the unit tests, and the resulting tests are automatically integrated into my IDE and Maven.

Preparations

Adding Scala Specs to my project turned out to be very easy. To begin with, I added the following dependencies:

<dependency>
  <groupId>org.scala-tools.testing</groupId>
  <artifactId>specs_2.8.0</artifactId>
  <version>1.6.5</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.8.1</version>
  <scope>test</scope>
</dependency>

I also added the following code to my plugin list, as described here:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <configuration>
    <includes>
      <include>**/*Spec.java</include>
    </includes>
  </configuration>
</plugin>

Testing the Producer

The next step was to convert my tests in the previous post to an actual unit test. So I created a new file called ProducerSpec in src/test/scala/nl/scalasim:

package nl.scalasim

import org.specs.SpecificationWithJUnit

/** Specification for Producers. */
class ProducerSpec extends SpecificationWithJUnit("Producers") {

  var producer: Actor = _

  "A Producer" should {

    doBefore {
      producer = new Producer("Test producer", "unobtainium")
      producer.start
    }

    doAfter {
      producer ! Stop
    }

    "react to Produce messages" in {
      producer !? Produce must be_==(Produced("unobtainium", 1))
    }

  }

}

I executed mvn test from the command line and enjoyment ensued.

The actual test starts at line 6, where I created a new class called ProducerSpec which extends org.specs.Specification. Well, actually it extends org.specs.SpecificationWithJUnit, but that's just to make Maven happy.

Inside this class, I wrote the specification, which basically follows this pattern:

"class to test" should {
  "conform to this" in { /* code block */ }
  "conform to that" in { /* code block */ }
  "etc etc etc" in { /* lather rinse repeat */ }
}

I don't pretend to know exactly what happens here, but basically the strings are descriptive syntactic sugar – the code blocks are what matter. And I find the result very readable.

Within the code blocks, I do what I always do: execute some code and compare the result to my expectations. Nothing much to see here. The construct must be_==(...) is just one of the many assertions supported by Specs. A full list can be found here.

The last thing to note are the doBefore and doAfter calls. These blocks are guaranteed to be called before and after running each specification-line, thus allowing for test fixtures.

Lessons Learned

The code above might seem easy, but once again I managed to learn a lot about Scala.

  • Sugar – the Scala syntax apparently allows for a lot of syntactic sugar; I can't remember having seen so much since I learned Scheme. I don't yet fully understand what happens in the tests, but the result is very cool.
  • Underscore – I hade already seen the underscore in pattern matching examples, signifying the I-don't-care-value, but it was nice to see that it can also be used in variable definitions such as
    var producer : Actor = _.
  • Lift – I haven't really looked into this, but it seems that if you need a well-supported framework, try to find a framework that is used by Lift. In my project, both the maven-scala-plugin and specs are used by Lift.

Get the code

The full code for this post can be found at code.google.com.

No comments:

Post a Comment