ScalaMock3 step-by-step

This post describes ScalaMock 3, which supports Scala 2.10 only. For ScalaMock 2, which supports earlier Scala versions, go here.


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


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.



Create a root directory for your project:
$ mkdir myproject[/soucecode]

Create build.sbt containing:
1organization := "com.example"

version := "1.0"

scalaVersion := "2.10.0"

scalacOptions = Seq("-deprecation", "-unchecked")

libraryDependencies =
"org.scalamock" %% "scalamock-scalatest-support" % "3.0" % "test"

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
}

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))
}
}

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 scala.math.{Pi, sqrt}

class ControllerTest extends FunSuite with MockFactory {

test("draw line") {
val mockTurtle = mock[Turtle]
val controller = new Controller(mockTurtle)

inSequence {
inAnyOrder {
(mockTurtle.penUp _).expects()
(mockTurtle.getPosition _).expects().returning(0.0, 0.0)
(mockTurtle.getAngle _).expects().returning(0.0)
}
(mockTurtle.turn _).expects(~(Pi / 4))
(mockTurtle.forward _).expects(~sqrt(2.0))
(mockTurtle.getAngle _).expects().returning(Pi / 4)
(mockTurtle.turn _).expects(~(-Pi / 4))
(mockTurtle.penDown _).expects()
(mockTurtle.forward _).expects(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.
Run the tests with sbt test:
$ sbt
> test
[info] ControllerTest:
[info] - draw line
[info] Passed: : Total 1, Failed 0, Errors 0, Passed 1, Skipped 0


 •  0 comments  •  flag
Share on Twitter
Published on October 14, 2012 10:06
No comments have been added yet.