Getting started with JUnit 3 in Scala

If you want to write JUnit 3 tests in Scala that you run with JUnit, you can enjoy more concise code by using ScalaTest's assertions and/or matchers. To use assertions, mix org.scalatest.junit.AssertionsForJUnit into your TestCase:

import junit.framework.TestCase
import org.scalatest.junit.AssertionsForJUnit
import scala.collection.mutable.ListBuffer
import junit.framework.Assert._

class ExampleSuite extends TestCase with AssertionsForJUnit {

  var sb: StringBuilder = _
  var lb: ListBuffer[String] = _

  override def setUp() {
    sb = new StringBuilder("ScalaTest is ")
    lb = new ListBuffer[String]
  }

  def testEasy() { // Uses JUnit-style assertions
    sb.append("easy!")
    assertEquals("ScalaTest is easy!", sb.toString)
    assertTrue(lb.isEmpty)
    lb += "sweet"
    try {
      "verbose".charAt(-1)
      fail()
    }
    catch {
      case e: StringIndexOutOfBoundsException => // Expected
    }
  }

  def testFun() { // Uses ScalaTest assertions
    sb.append("fun!")
    assert(sb.toString === "ScalaTest is fun!")
    assert(lb.isEmpty)
    lb += "sweeter"
    intercept[StringIndexOutOfBoundsException] {
      "concise".charAt(-1)
    }
  }
}
Note: JUnit differentiates between exceptions resulting from assertions, which it calls failures, and unexpected exceptions, which it calls errors. By mixing in org.scalatest.junit.AssertionsForJUnit, you ensure JUnit will report failures of ScalaTest assertions as failures not errors.

You can see the difference in conciseness between the JUnit assertions used by testEasy and the ScalaTest assertions used by testFun. If you compile this class with the Scala compiler, JUnit will happily run the resulting class file. Here's how you compile it:

scalac -cp scalatest-1.5.jar:junit-4.4.jar ExampleSuite.scala

Here's one way to run it using JUnit:

$ scala -cp .:scalatest-1.5.jar:junit-4.4.jar junit.textui.TestRunner ExampleSuite
..
Time: 0.032

OK (2 tests)

If you wish to give yourself the option of running with either JUnit or ScalaTest, mix in org.scalatest.junit.JUnit3Suite. Trait JUnit3Suite is already a junit.framework.TestCase and already mixes in AssertionsForJUnit:

import org.scalatest.junit.JUnit3Suite
import scala.collection.mutable.ListBuffer
import junit.framework.Assert._

class ExampleSuite extends JUnit3Suite {

  var sb: StringBuilder = _
  var lb: ListBuffer[String] = _

  override def setUp() {
    sb = new StringBuilder("ScalaTest is ")
    lb = new ListBuffer[String]
  }

  def testEasy() { // Uses JUnit-style assertions
    sb.append("easy!")
    assertEquals("ScalaTest is easy!", sb.toString)
    assertTrue(lb.isEmpty)
    lb += "sweet"
    try {
      "verbose".charAt(-1)
      fail()
    }
    catch {
      case e: StringIndexOutOfBoundsException => // Expected
    }
  }

  def testFun() { // Uses ScalaTest assertions
    sb.append("fun!")
    assert(sb.toString === "ScalaTest is fun!")
    assert(lb.isEmpty)
    lb += "sweeter"
    intercept[StringIndexOutOfBoundsException] {
      "concise".charAt(-1)
    }
  }
}

Because ExampleSuite is still a JUnit TestCase, it can still be run with JUnit:

$ scala -cp .:scalatest-1.5.jar:junit-4.4.jar junit.textui.TestRunner ExampleSuite
..
Time: 0.032

OK (2 tests)

But because it is also a ScalaTest Suite, you can now also run it with ScalaTest:

$ scala -cp scalatest-1.5.jar:junit-4.4.jar org.scalatest.tools.Runner -p . -o -s ExampleSuite
Run starting. Expected test count is: 2
ExampleSuite:
- testFun(ExampleSuite)
- testEasy(ExampleSuite)
Run completed in 189 milliseconds.
Total number of tests run: 2
Suites: completed 1, aborted 0
Tests: succeeded 2, failed 0, ignored 0, pending 0
All tests passed.

One final variation you may wish to try is to use ScalaTest's matchers DSL. Simply mix in ShouldMatchersForJUnit (or MustMatchersForJUnit if you prefer "must" to "should"). Here's an example:

import org.scalatest.junit.JUnit3Suite
import org.scalatest.junit.ShouldMatchersForJUnit
import scala.collection.mutable.ListBuffer
import junit.framework.Assert._

class ExampleSuite extends JUnit3Suite with ShouldMatchersForJUnit {

  var sb: StringBuilder = _
  var lb: ListBuffer[String] = _

  override def setUp() {
    sb = new StringBuilder("ScalaTest is ")
    lb = new ListBuffer[String]
  }

  def testEasy() { // Uses ScalaTest assertions
    sb.append("easy!")
    assert(sb.toString === "ScalaTest is easy!")
    assert(lb.isEmpty)
    lb += "sweet"
    intercept[StringIndexOutOfBoundsException] {
      "concise".charAt(-1)
    }
  }

  def testFun() { // Uses ScalaTest matchers
    sb.append("fun!")
    sb.toString should be ("ScalaTest is fun!")
    lb should be ('empty)
    lb += "sweeter"
    evaluating { "clear".charAt(-1) } should produce [StringIndexOutOfBoundsException]
  }
}

As before, you can run this class with either JUnit or ScalaTest:

$ scala -cp .:scalatest-1.5.jar:junit-4.4.jar junit.textui.TestRunner ExampleSuite
..
Time: 0.082

OK (2 tests)

$ scala -cp scalatest-1.5.jar:junit-4.4.jar org.scalatest.tools.Runner -p . -o -s ExampleSuite
Run starting. Expected test count is: 2
ExampleSuite:
- testFun(ExampleSuite)
- testEasy(ExampleSuite)
Run completed in 116 milliseconds.
Total number of tests run: 2
Suites: completed 1, aborted 0
Tests: succeeded 2, failed 0, ignored 0, pending 0
All tests passed.

ScalaTest is brought to you by Bill Venners, with contributions from several other folks. It is sponsored by Artima, Inc.
ScalaTest is free, open-source software released under the Apache 2.0 license.

Copyright © 2009-2011 Artima, Inc. All Rights Reserved.

artima