Wednesday 13 January 2010

Using SBT on your Scala Maven project for continous testing

Continuous testing is the practice of rerunning test cases whenever you change source code. Its a great way to write code in a mostly test-first way and it gives you very rapid feedback as you change code.

It can take a while to rebuild & rerun tests on a Scala project when using Maven (and IDEs can be a little slow sometimes too when it comes to continuous testing and scala).

You can buy Infinitest as an IDE plugin which is triggered whenever you do a build. Though I've found the console view isn't great when running ScalaTests (there's no way to navigate to the code that fails) - and you have to explicitly hit 'build' when you're editing your code. I prefer tests to just rerun automatically (reusing IDEA's auto-save feature).

So another approach is to use sbt, the simple build tool for scala.

Installing sbt
I use 0.6.9 (or xsbt as its often called) so I can work with scala 2.8.0.Beta1-RC7 nicely. Basically download the jar and create script called 'sbt' or 'xsbt' if you prefer, then you can run sbt from the command line.

You can then run sbt in the directory of your pom.xml and it'll configure itself with whatever project & version you want to use and version of sbt/scala etc.

Setting up sbt for maven projects
For those new (like me) to sbt, here's a quick way to get your maven build converted to use sbt. If you don't have a maven build for your project you can skip this step.

To cut corners and not configure all the maven repos you want to use to download your dependencies, you can just let sbt reuse your local maven repo to find jars.

So create a scala file in the project/build directory. sbt will have created the project directory for you, along with a boot subdirectory but you will need to create the build directory.

Call the file whatever you like, such as project/build/Foo.scala...
import sbt._

class FooProject(info: ProjectInfo) extends DefaultProject(info) {

val mavenLocal = "Local Maven Repository" at
"file://"+Path.userHome+"/.m2/repository"
}
Now you can start sbt and update it to load all the maven dependencies from your project

sbt
update
compile

The first execution of sbt puts you in the sbt shell which has completion and help so you can find the various options available. The 'update' task loads & downloads all the dependencies from your pom.xml. Refer to the docs for more details on repositories and dependencies.

Now you've got your dependencies imported, lets do some continuous testing.

Continuous Testing
From the sbt shell just type
~ test
Now sbt will monitor your code, detect when its changed, rebuild and rerun all the tests for you showing the results in nicely colour coded output in the terminal.

When you fancy playing in the Scala interactive shell (REPL) just type

console-project

And you're good to go. Enjoy!

Have you figured out a neater way of doing continuous testing with IDEA and Scala?

I guess someone could hack a JRebel plugin for Maven so that you could use the scala:cc goal to incrementally compile your scala code as you edit it; then JRebel automatically reloads the changed classes, then the new continuous testing plugin would just need to use a trigger in the JRebel SDK so that when a class is reloaded it reruns the relevant test cases (or all of them - maybe sorted by previously failed ones first).

A similar technique works great when running projects with jetty:run or scala:console - letting JRebel reload any classes rebuilt via scala:cc