Archive Page 3

Formula Jedi 2012 Calendar

07-08 Apr: Silverstone National
12-13 May: Anglesey
02-03 Jun: Cadwell Park
21-22 July: Snetterton (200 & 300)
18-19 Aug: Rockingham
01 Sep: Oulton Park (International)
20-21 Oct: Donington Park

ScalaMock 2.2

I’ve just released ScalaMock 2.2, with the following improvements over 2.1:

  • Add support for repeated parameters (varargs)
  • Basic parameterised class support

ScalaMock is a native Scala mocking framework which, as well as traits (interfaces) and functions, can also mock:

  • Classes
  • Singleton and companion objects (static methods)
  • Object creation (constructor invocation)
  • Polymorphic (type parameterised) methods
  • Classes with private constructors
  • Final classes and classes with final methods
  • Operators (methods with symbolic names)
  • Overloaded methods

ScalaMock 2.1

I’ve just released ScalaMock 2.1, with the following improvements over 2.0:

  • Add support for polymorphic (type parameterised) methods
  • Add support for curried methods
  • Fix String constants in Java classes
  • Fix unmocked operators

ScalaMock is a native Scala mocking framework which, as well as traits (interfaces) and functions, can also mock:

  • Classes
  • Singleton and companion objects (static methods)
  • Object creation (constructor invocation)
  • Polymorphic (type parameterised) methods
  • Classes with private constructors
  • Final classes and classes with final methods
  • Operators (methods with symbolic names)
  • Overloaded methods

ScalaMock step-by-step

This post describes ScalaMock 2, which is no longer under development. For the current development version, go here.

ScalaMock (previously Borachio) is a mocking library for Scala. As well as traits (interfaces) and functions, it can also mock:

  • Classes
  • Singleton and companion objects (static methods)
  • Object creation (constructor invocation)
  • Classes with private constructors
  • Final classes and classes with final methods
  • Operators (methods with symbolic names)
  • Overloaded methods

This post describes how to setup a project that uses ScalaMock in conjunction with ScalaTest and sbt 0.11. The sample code described in this article is available on GitHub.

Note: If you only want to mock functions and traits (interfaces), you can use ScalaMock’s proxy mocks by simply linking with the .jar file – no need to use the compiler plugin or sbt plugin described below.

The example assumes that we’re writing code to control a mechanical turtle, similar to that used by Logo programs. Mocking is useful in this kind of situation because we might want to create tests that function even if we don’t have the hardware to hand, which run more quickly than would be the case if we ran on real hardware, and where we can use mocks to simulate errors or other situations difficult to reproduce on demand.

Getting started

  1. Create a root directory for your project:
    $ mkdir myproject
  2. ScalaMock uses a compiler plugin to generate code. There’s an sbt plugin that makes setting this up easy. Add this plugin to your project by creating project/project/Build.scala containing:
    import sbt._
    object PluginDef extends Build {
      override lazy val projects = Seq(root)
      lazy val root = Project("plugins", file(".")) dependsOn(scalamockPlugin)
      lazy val scalamockPlugin = uri("git://github.com/paulbutcher/scalamock-sbt-plugin")
    }
  3. Create project/Build.scala containing:
    import sbt._
    import Keys._
    import ScalaMockPlugin._
    
    object MyBuild extends Build {
    
      override lazy val settings = super.settings ++ Seq(
        organization := "com.example",
        version := "1.0",
        scalaVersion := "2.9.1",
    
        resolvers += ScalaToolsSnapshots,
        libraryDependencies += "org.scalamock" %% "scalamock-scalatest-support" % "2.0-SNAPSHOT",
        autoCompilerPlugins := true,
        addCompilerPlugin("org.scalamock" %% "scalamock-compiler-plugin" % "2.0-SNAPSHOT"))
    
      lazy val myproject = Project("MyProject", file(".")) settings(generateMocksSettings: _*) configs(Mock)
    }

Simple mocking

  1. Now we’ve got a project, we need some code to test. Let’s start with a simple trait representing a turtle. Create src/main/scala/Turtle.scala containing:
    package com.example
    
    trait Turtle {
      def penDown()
      def penUp()
      def forward(distance: Double)
      def turn(angle: Double)
      def getPosition: (Double, Double)
      def getAngle: Double
    }
  2. The turtle API is not very convenient, we have no way to move to a specific position, instead we need to work out how to get from where we are now to where we want to get by calculating angles and distances. Here’s some code that draws a line from a specific point to another by doing exactly that.

    Create src/main/scala/Controller.scala containing:

    package com.example
    
    import scala.math.{atan2, sqrt}
    
    class Controller(turtle: Turtle) {
    
      def drawLine(start: (Double, Double), end: (Double, Double)) {
        moveTo(start)
    
        val initialAngle = turtle.getAngle
        val deltaPos = delta(start, end)
    
        turtle.turn(angle(deltaPos) - initialAngle)
        turtle.penDown
        turtle.forward(distance(deltaPos))
      }
    
      def delta(pos1: (Double, Double), pos2: (Double, Double)) =
        (pos2._1 - pos1._1, pos2._2 - pos1._2)
    
      def distance(delta: (Double, Double)) =
        sqrt(delta._1 * delta._1 + delta._2 * delta._2)
    
      def angle(delta: (Double, Double)) =
        atan2(delta._2, delta._1)
    
      def moveTo(pos: (Double, Double)) {
        val initialPos = turtle.getPosition
        val initialAngle = turtle.getAngle
    
        val deltaPos = delta(initialPos, pos)
    
        turtle.penUp
        turtle.turn(angle(deltaPos) - initialAngle)
        turtle.forward(distance(deltaPos))
      }
    }
  3. In order to create mock turtles, we need to tell ScalaMock to generate the appropriate code by using the @mock annotation. Create src/generate-mocks/scala/GenerateMocks.scala containing:
    package com.example
    
    import org.scalamock.annotation.mock
    
    @mock[Turtle]
    class Dummy
  4. We can now write a test. We’ll create a mock turtle that pretends to start at the origin (0, 0) and verifies that if we draw a line from (1, 1) to (2, 1) it performs the correct sequence of turns and movements.

    Turtle diagram

    Create src/test/scala/ControllerTest.scala containing:

    package com.example
    
    import org.scalatest.FunSuite
    import org.scalamock.scalatest.MockFactory
    import org.scalamock.generated.GeneratedMockFactory
    import scala.math.{Pi, sqrt}
    
    class ControllerTest extends FunSuite with MockFactory with GeneratedMockFactory {
    
      test("draw line") {
        val mockTurtle = mock[Turtle]
        val controller = new Controller(mockTurtle)
    
        inSequence {
          inAnyOrder {
            mockTurtle.expects.penUp
            mockTurtle.expects.getPosition returning (0.0, 0.0)
            mockTurtle.expects.getAngle returning 0.0
          }
          mockTurtle.expects.turn(~(Pi / 4))
          mockTurtle.expects.forward(~sqrt(2.0))
          mockTurtle.expects.getAngle returning Pi / 4
          mockTurtle.expects.turn(~(-Pi / 4))
          mockTurtle.expects.penDown
          mockTurtle.expects.forward(1.0)
        }
    
        controller.drawLine((1.0, 1.0), (2.0, 1.0))
      }
    }

    This should (hopefully!) be self-explanatory, with one possible exception. The tilde (~) operator represents an epsilon match, useful for taking account of rounding errors when dealing with floating-point values.

  5. Generate mocks with generate-mocks and then run the tests with test:
    $ sbt
    > generate-mocks
    [log generatemocks] Creating mock for: trait Turtle
    > test
    [info] ControllerTest:
    [info] - draw line
    [info] Passed: : Total 1, Failed 0, Errors 0, Passed 1, Skipped 0

Getting clever: Constructors and singleton objects

  1. Turtles use ink. Let’s define a singleton object that keeps track of how much we’ve used.

    Create src/main/scala/InkReservoir.scala containing:

    package com.example
    
    object InkReservoir {
    
      def use(r: Double, g: Double, b: Double) {
        red -= r
        green -= g
        blue -= b
      }
    
      private var red = 10.0
      private var green = 10.0
      private var blue = 10.0
    }
  2. And now let’s create a concrete implementation of our Turtle trait, which adds the ability to define a pen colour, together with a factory method implemented in its companion object.

    Create src/main/scala/ColouredTurtle.scala containing:

    package com.example
    
    import scala.math.{cos, sin}
    
    class ColouredTurtle(r: Double, g: Double, b: Double) extends Turtle {
      def penDown() { penIsDown = true }
      def penUp() { penIsDown = false }
      def turn(angle: Double) { theta += angle}
      def getPosition: (Double, Double) = (x, y)
      def getAngle: Double = theta
      def forward(d: Double) {
        x += sin(theta) * d
        y += cos(theta) * d
        if (penIsDown)
          InkReservoir.use(r * d, g * d, b * d)
      }
    
      private var penIsDown = false
      private var x = 0.0
      private var y = 0.0
      private var theta = 0.0
    }
    
    object ColouredTurtle {
    
      def apply(colour: Symbol) = {
        val (r, g, b) = colourMap(colour)
        new ColouredTurtle(r, g, b)
      }
    
      private val colourMap = Map('red -> (1.0, 0.0, 0.0), 'green -> (0.0, 1.0, 0.0), 'blue -> (0.0, 0.0, 1.0))
    }
  3. To mock ColouredTurtle, first we need to add another @mock annotation to GenerateMocks.scala:
    @mock[ColouredTurtle]
  4. We can now write a test to verify that our factory method works.

    Create src/test/scala/ColouredTurtleTest.scala:

    package com.example
    
    import org.scalatest.FunSuite
    import org.scalamock.scalatest.MockFactory
    import org.scalamock.generated.GeneratedMockFactory
    
    class ColouredTurtleTest extends FunSuite with MockFactory with GeneratedMockFactory {
    
      test("coloured turtles") {
        val m1 = mock[ColouredTurtle]
        val m2 = mock[ColouredTurtle]
    
        m1.expects.newInstance(1.0, 0.0, 0.0)
        m2.expects.newInstance(0.0, 1.0, 0.0)
        m2.expects.forward(3.0)
    
        val t1 = ColouredTurtle('red)
        val t2 = ColouredTurtle('green)
        t2.forward(3.0)
      }
    }
  5. Run the tests again (don’t forget to run generate-mocks first) to see:
    [info] ColouredTurtleTest:
    [info] - coloured turtles
    [info] ControllerTest:
    [info] - draw line
    [info] Passed: : Total 2, Failed 0, Errors 0, Passed 2, Skipped 0
  6. Finally, we can add a test to verify that we’re keeping track of ink correctly. Let ScalaMock know that we’ll be mocking InkReservoir by adding a @mockObject annotation:
    @mockObject(InkReservoir)</pre>
    
    And add a test to <code>ColouredTurtleTest.scala</code>:
    
    <pre>  test("ink reservoir") {
        val m = mockObject(InkReservoir)
    
        m.expects.use(0.0, 3.0, 0.0)
    
        val t = ColouredTurtle('green)
        t.penDown
        t.forward(3.0)
      }
  7. [info] ControllerTest:
    [info] - draw line
    [info] ColouredTurtleTest:
    [info] - coloured turtles
    [info] - ink reservoir
    [info] Passed: : Total 3, Failed 0, Errors 0, Passed 3, Skipped 0

Scala 2.9.1, sbt 0.10 and ScalaTest step-by-step

Some while ago, I wrote a post about getting Scala 2.8.0.RC1, sbt and ScalaTest to work together. Well, things have moved on somewhat since then, so I thought it was time to update it.

  1. Install sbt 0.10.1
  2. Create the root directory for your project:
    $ mkdir aproject
  3. Create a settings file in this directory called build.sbt containing:
    name := "A Project"
    
    version := "0.1"
    
    scalaVersion := "2.9.1"
    
    libraryDependencies ++= Seq(
      "org.scalatest" %% "scalatest" % "1.6.1" % "test"
    )
  4. Create src/main/scala/Widget.scala containing:
    package com.example
    
    class Widget {
      def colour = "Blue"
      def disposition = "Awesome"
    }
  5. Create src/test/scala/WidgetTest.scala containing:
    package com.example.test
    
    import org.scalatest.FunSuite
    import com.example.Widget
    
    class WidgetTest extends FunSuite {
    
      test("colour") {
        expect("Blue") { new Widget().colour }
      }
    
      test("disposition") {
        expect("Awesome") { new Widget().disposition }
      }
    }
  6. Run your tests with sbt test. You should see:
    [info] WidgetTest:
    [info] - colour
    [info] - disposition
    [info] Passed: : Total 2, Failed 0, Errors 0, Passed 2, Skipped 0
  7. Create src/main/scala/Main.scala containing:
    package com.example
    
    object Main {
      def main(args: Array[String]) {
        val w = new Widget()
        println("My new widget is "+ w.colour)
      }
    }
  8. Run your program with sbt run. You should see:
    [info] Running com.example.Main
    My new widget is Blue

"Power" mocking in Scala with Borachio

The work described in this post has now been released in ScalaMock.

Over the last few weeks, I’ve been working on major enhancements for Borachio (my native mocking library for Scala) to add facilities similar to those provided by PowerMock for Java. As well as interfaces and functions, it can now mock:

  • Classes
  • Final classes and classes with final methods
  • Classes with private constructors
  • Singleton (companion) objects
  • Object creation (i.e. new)

And, as an extra bonus, mocks are now typesafe :-).

It’s not completely finished yet, but it is close enough that it’s worth soliciting feedback. The code is available on GitHub and a snapshot is available on scala-tools.

Warning: Although this is getting close to “done”, the details may change slightly before final release.

So what does this look like in action? I’m going to demonstrate with a slightly modified version of Martin Fowler’s “warehouse” example from Mocks Aren’t Stubs. This example is available on GitHub. First, here’s a Warehouse object (a Scala singleton object):

object Warehouse {
  val products = Map(("Talisker" -> 5), ("Lagavulin" -> 2))

  def hasInventory(product: String, quantity: Int) =
    inStock(product) >= quantity

  def remove(product: String, quantity: Int) =
    products += (product -> (inStock(product) - quantity))

  def inStock(product: String) = products.getOrElse(product, 0)
}

And here’s an Order class that removes things from the warehouse:

class Order(product: String, quantity: Int) {
  var filled = false

  def fill() {
    if (Warehouse.hasInventory(product, quantity)) {
      Warehouse.remove(product, quantity)
      filled = true
    }
  }
}

object Order {
  def apply(product: String, quantity: Int) =
    new Order(product, quantity)

  def largestPossible(product: String) = {
    val quantity = Warehouse.inStock(product)
    new Order(product, quantity)
  }
}

First, let’s see how we can go about testing the Order class by mocking the Warehouse object:

test("Enough stock") {
  val mockWarehouse = mockObject(Warehouse)

  mockWarehouse.expects.hasInventory("Talisker", 50) returning true
  mockWarehouse.expects.remove("Talisker", 50)

  val order = Order("Talisker", 50)
  order.fill

  assert(order.filled)
}

The “magic” happens in the mockObject call:

  val mockWarehouse = mockObject(Warehouse)

This returns a mock version of the Warehouse object upon which expectations can be set. From that point onwards, the code should be pretty self-explanatory.

Another example, this time of mocking object creation:

test("Order everything") {
  val mockWarehouse = mockObject(Warehouse)
  val mockOrder = mock[Order]

  mockWarehouse.expects.inStock("Laphroig") returning 10
  mockOrder.expects.newInstance("Laphroig", 10)

  Order.largestPossible("Laphroig")
}

This uses two mock objects, one representing the Warehouse object and one representing an (as yet uncreated) instance of the Order class:

  val mockWarehouse = mockObject(Warehouse)
  val mockOrder = mock[Order]

The interesting line is this one:

  mockOrder.expects.newInstance("Laphroig", 10)

Which sets an expectation that a new instance of the Order class will be created with constructor arguments ("Laphroig", 10).

Building

Most of the cleverness happens within a Scala compiler plugin. Compiling tests that use mocks requires three steps:

  1. Compile the code you want to test as normal.
  2. Compile this code again with the Borachio compiler plugin enabled. The plugin will generate mock source code for any classes and objects mentioned in @mock @mockObject annotations.
  3. Compile this code together with your test code

These steps have all been collected into an sbt plugin, so all you need to do is mix the GenerateMocks trait into your project definition and everything else should happen automagically.

Under the hood

Given the Order class in our example above, the compiler plugin generates two different classes, one with the same name (i.e. Order) and one called Mock$Order. Here’s (a simplified version of) what they look like:

class Order(dummy: MockConstructorDummy) extends Mock$Order {

  def fill(): Unit = mock$0()
  def this(product: String, quantity: Int) = {
    this(new MockConstructorDummy)
    mock$1(product, quantity)
  }

  lazy val mock$0 = new MockFunction0[Unit]
  lazy val mock$1 = new MockConstructor2[String, Int, Order]
}

trait Mock$Order {

  val expects = new {
    def fill() = mock$0.expects()
    def newInstance(product: String, quantity: Int) =
      mock$1.expects(product, quantity)

    lazy val mock$0 = // reference to mock$0 in Order
    lazy val mock$1 = // reference to mock$1 in Order
  }
}

Borachio then uses a custom class loader to ensure that, when the code being tested tries to load the Order class, it gets the generated version above (calls get forwarded to the “real” Order class if mocking isn’t in force).

To do

I hope that this code is complete enough to be useful. Certainly it’s complete enough that I’d welcome feedback on anything that doesn’t work or could be done better. The things that still need doing are:

  • Android and JUnit3 integration
  • Support for mocking private constructors and methods
  • Forwarding to non-mock singleton functionality (this is in place for classes, not yet for singleton objects)
  • Static method (Java) support
  • Support for type-parameterised methods

Video: Mocking, Testing and Dependency Injection

A video of Chetan Padia talking about Mocking, Testing and Dependency Injection at Londroid.