Working With Scala Test


Scala Test is an open source Test framework for the java platform. With Scala test we can either test java or Scala code. It integrates with popular existing tools like JUnit, TestNG and it is designed to do different styles of testing like Behavior Driven Design for example.

Let’s have a look at a simple JUnit4 Test in Scala Test

package com.inphina.ibat.junit

import org.scalatest.junit.AssertionsForJUnit
import org.junit.Assert._
import org.junit.Test
import  org.junit.Before

class SimpleJunit4Demo extends AssertionsForJUnit {

  var sb: StringBuilder = _

  @Before def initialize() {
    sb = new StringBuilder("Welcome To ")
  }

  @Test
  def verifyEasy() {
    sb.append("ScalaTest!")
    assertEquals("Welcome To ScalaTest!", sb.toString)
  }

}

This Test implementation is not very different from a normal JUnit Test we are accustomed to. In order to understand ScalaTest there are three concepts we need to be aware of.

  • Suite: A collection of tests. A Test is anything that has a name and can succeed or fail
  • Runner: ScalaTest provides a Runner application that can run Suites of Tests
  • Reporter: As Tests are run events are fired to a reporter, it takes care of presenting results back to the user

Let’s have a bit more detailed look at the Suite which is a Trait.

Suite

When you run a Test in Scala Test you basically invoke run(Option[String], Reporter, .. ) on Suite Object.

  • It then calls runNestedSuites(Reporter, ..).
  • And it calls runTests(Option[String], Reporter, ..)

runNestedSuites(Reporter, ..) then invokes nestedSuites() : List[Suite] to get a List of nested Suites. Which are required for running tests.

runTests(Option[String], Reporter, ..) calls def testNames: Set[String] to get a Set of test names it needs to run. For each test name it calls runTest(Reporter, …) It wraps the test code as a Function Object with a name and passes it to withFixture(NoArgTest) which actually runs the test.

Way of working with Scala Test is working with Traits. Just like any other Trait we can do Mixin composition to have a different flavor of Tests we want to. Scala Test have some core Traits and then we can mix it with other available Traits.

Core Traits

Mix In other Traits

So, essentially working with Scala Test requires picking up a Core Trait and mixin it with other provided Traits. Some of the Core Traits are

  • Suite
  • FunSuite
  • Spec
  • FlatSpec
  • WordSpec
  • FeatureSpec

Let’s have a look at a Suite Example:
Traits approach to writing tests. Simply create classes extending Suite and define test methods. Test methods have names testXXXX. All methods must be public. Scala Test provides === operator. It is defined in Traits Assertions. Allows the failure report to include both right and left values.

package com.inphina.ibat.suite

import org.scalatest.Suite

/**
 * Traits approach to writing tests. Simply create classes
 * extending Suite and define test methods.
 *
 * Test methods have names testXXXX. All methods must be public.
 *
 * Scala Test provides === operator. It is defined in Traits Assertions. Allows the failure report
 * to include both right and left values.
 */

class SimpleSuiteDemo extends Suite {

   def testAddition() {
        val sum = 1 + 1
        assert(sum === 3)
   }

  def testSubtraction() {
    val diff = 4 - 1
    assert(diff === 3)
  }
}

If we want to have some Mixin with other Traits in Scala Test then we can use ShouldMatchers. It provides DSL type of assertions and makes the code much more readable. Let’s have a look at the code listing below.

package com.inphina.ibat.suite

import org.scalatest.Suite
import org.scalatest.matchers.ShouldMatchers

/**
 * Mixin Traits ShouldMatchers for DSl type assertions
 */

class DSLMatchersSuiteDemo extends Suite with ShouldMatchers {

  def testAddition() {
    val sum = 1 + 1
    sum should equal (2)
    sum + 2 should equal (4)
  }

}

Both the Tests till now are not purely functional Tests. They resemble normal Java Tests use FunSuite Trait to write Functional Scala Tests.
FunSuite

  • “test” is a method defined in FunSuite Trait. Test name goes in parentheses and the test code goes in curly braces
  • The test code in curly braces is passed as a by-name parameter to “test” method which registers for later execution
  • A FunSuite’s life-cycle has two phases: the registration phase and the ready phase

Let’s have a look at the code example

package com.inphina.ibat.funsuite

import org.scalatest.FunSuite

/**
 * For writing Functional Tests use FunSuite Fun => Functional Suite. "test" is a method defined in FunSuite Trait.
 * Test name goes in parentheses and the test code goes in curly braces. One benefit of using FunSuite compared to
 * Suite is that we need not name the test with testXXXX style names.
 *
 * The test code in curly braces is passed as a by-name parameter to "test" method which registers for later execution
 *
 * More benefits we can easily give long names in tests instead of camel case notation generally used.
 *
 * A FunSuite's life-cycle has two phases: the registration phase and the ready phase. It starts in registration phase
 * and enters ready phase the first time run is called on it. It then remains in ready phase for the remainder of its
 * lifetime.
 */

class SimpleFunSuiteDemo extends FunSuite {

  test("addition of numbers") {
    val sum = 1 + 2
    assert(sum === 2)
  }

  test("subtraction") {
    val diff = 5 - 2
    assert(diff === 3)
  }

}

One of the immediate benefits is that we can use more descriptive test names instead of Camel case method names we are so used to.

We have looked at Suite and FunSuite way of writing tests now lets have a look at the FeatureSpec which is a higher level way of writing Tests. It basically represents a Suite of Tests where each Test represent a scenario of a Feature.

A FeatureSpec contains feature clauses and scenarios. Feature Clause and Scenario are defined by “feature” and “scenario”. Both of them are defined as methods in FeatureSpec.
Let’s have a look at an example of FeatureSpec mixin with GivenWhenThen Trait.

package com.inphina.ibat.featurespec

import org.scalatest.FeatureSpec
import org.scalatest.GivenWhenThen
import scala.collection.mutable.Stack


class StackFeatureSpec extends FeatureSpec with GivenWhenThen {

  feature("The user can pop an element off the top of the stack") {

    info("As a programmer")
    info("I want to be able to pop items off the stack")
    info("So that I can get them in last-in-first-out order")

    scenario("pop is invoked on a non-empty stack") {

      given("a non-empty stack")
      val stack = new Stack[Int]
      stack.push(1)
      stack.push(2)
      val oldSize = stack.size

      when("when pop is invoked on the stack")
      val result = stack.pop()

      then("the most recently pushed element should be returned")
      assert(result === 2)

      and("the stack should have one less item than before")
      assert(stack.size === oldSize - 1)
    }

    scenario("pop is invoked on an empty stack") {

      given("an empty stack")
      val emptyStack = new Stack[String]

      when("when pop is invoked on the stack")
      then("NoSuchElementException should be thrown")
      intercept[NoSuchElementException] {
        emptyStack.pop()
      }

      and("the stack should still be empty")
      assert(emptyStack.isEmpty)
    }
  }
}

Major benefits by Scala Test are similar to scala itself. It is concise, provides you a flexible manner of testing your application be it Scala or Java. Works with popular Java frameworks like TestNg and JUnit and EasyMock. And last but not the least provides a nice way to introduce Scala in the project.

Advertisements
This entry was posted in Scala and tagged , . Bookmark the permalink.

One Response to Working With Scala Test

  1. To me that is just ignorant and I immediately perhaps wrongly assume that the.person making that statement do not routinely test-drive his code. I have an idea to use scalas parser-library to rewrite a javaCC-generated parser for a simple rule-matching syntax in pure scala..I will kick out specs and try scala-test instead..Ill continue to think about the best way to introduce scala in an assignment without scaring people .

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s