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.

  1. Create a root directory for your project:
    $ mkdir myproject[/soucecode]
    </li>
    	<li>Create <code>build.sbt</code> containing:
    1organization := "com.example"
    
    version := "1.0"
    
    scalaVersion := "2.10.0"
    
    scalacOptions ++= Seq("-deprecation", "-unchecked")
    
    libraryDependencies +=
      "org.scalamock" %% "scalamock-scalatest-support" % "3.0" % "test"
  2. 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
    }
  3. 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))
      }
    }
  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 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.

  5. 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

5 Responses to “ScalaMock3 step-by-step”


  1. 1 Michael Hamrah April 28, 2013 at 6:27 pm

    Is there a way to stub objects as with ScalaMock2? Can’t seem to find the correct imports.

    Thanks,

    Mike

  2. 3 Ashwin December 19, 2013 at 2:10 pm

    Hi I have the ditto question – how to mock companion objects or class in this version. Pls guide.

    • 4 paulbutcher December 20, 2013 at 10:03 am

      Ashwin,

      Apologies – there is no way to do this with ScalaMock3 as thing currently stand. There are, sadly, restrictions in Scala’s macro system that are currently getting in the way of adding this, and other features. I’ve not had a chance to look at ScalaMock for several months thanks to working on the “Seven Concurrency Models” book. I hope to be able to look at it again in the new year.


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





Follow

Get every new post delivered to your Inbox.

Join 219 other followers

%d bloggers like this: