ScalaTest User Guide

Getting started

Selecting testing styles

Defining base classes

Writing your first test

Using assertions

Tagging your tests

Running your tests

Sharing fixtures

Sharing tests

Using matchers

Testing with mock objects

Property-based testing

Using Selenium

Other goodies

Philosophy and design

Migrating to 2.0

Testing with mock objects

You can use any Java mocking framework with ScalaTest, or ScalaMock, a Scala mocking alternative. ScalaTest provides just enough syntax sugar for the three most popular Java mocking frameworks—JMock, EasyMock, and Mockito—to remove boilerplate and clarify the client code. But other than this minor syntax sugar, the libraries are used from Scala as they are in Java. This enables people familiar with a particular framework to get going quickly and enhances readability for combined Java/Scala projects using a common mocking framework. ScalaMock, the native Scala mocking framework, has been designed to integrate easily into ScalaTest suites.

Here are links to the mocking frameworks described on this page:

Using ScalaMock

ScalaMock is a native, open-source Scala mocking framework written by Paul Butcher that allows you to mock objects and functions. ScalaMock supports three different mocking styles:

  • Function mocks
  • Proxy (dynamic) mocks
  • Generated (type-safe) mocks

To use ScalaMock, mix org.scalamock.scalatest.MockFactory into your Suite class, as in:

import org.scalatest.FlatSpec
import org.scalamock.scalatest.MockFactory

class ExampleSpec extends FlatSpec with MockFactory with ...

Function mocks

Function mocks are created with mockFunction. The following, for example, creates a mock function taking a single Int argument and returning a String:

val m = mockFunction[Int, String]

You can then set expectations set on the mock function. For example, here's how you'd state that you expect your mock to be called once with the argument 42, and that when called like that it should return the string "Forty two":

m expects (42) returning "Forty two" once

Proxy mocks

Proxy mocks can only be used to mock Scala traits and Java interfaces. (To mock classes, singleton/companion objects etc., please use generated mocks.) To use proxy mocks, mix org.scalamock.ProxyMockFactory into your test suite. Proxy mocks are created with mock. The following, for example, creates a mock that implements all the Turtle trait (interface):

val m = mock[Turtle]

You can then set expectations on each of the methods within those traits. Here's an example:

m expects 'setPosition withArgs (10.0, 10.0)
m expects 'forward withArgs (5.0)
m expects 'getPosition returning (15.0, 10.0)

By default, an expectation accepts any arguments and a single call. The following two statements are equivalent:

m expects 'forward withArgs (*) once
m expects 'forward

As a convenience, proxy mocks also support the stubs method. The following two statements are equivalent:

m expects 'forward anyNumberOfTimes
m stubs 'forward

Generated mocks

Generated mocks rely on the ScalaMock compiler plugin. Classes that are going to be mocked need to be declared with the org.scalamock.annotation.mock annotation. To mock a class together with its companion object, use org.scalamock.annotation.mockWithCompanion. To mock a standalone singleton object, use org.scalamock.annotation.mockObject.

In addition to MockFactory, your test class also needs to mix in GeneratedMockFactory.

Then, to create a regular mock object, use mock:

val m = mock[Turtle]

m.expects.forward(10.0) twice

To mock a singleton or companion object, use mockObject:

val m = mockObject(Turtle)

m.expects.createTurtle

And to mock a constructor invocation, use newInstance:

val m = mock[Turtle]

m.expects.newInstance('blue)
m.expects.forward(10.0)

Expectations

You can specify expectations about the arguments with which a function or method is called and how many times it will be called. In addition, you can instruct a mock to return a particular value or throw an exception when that expectation is met.

Arguments

To specify expected arguments for a functional mock, use expects. To specify expected arguments for a proxy mock, use withArgs or withArguments.

If no expected arguments are given, mocks accept any arguments.

To specify arguments that should simply be tested for equality, provide the expected arguments as a tuple:

m expects ("this", "that")

ScalaMock currently supports two types of generalized matching: wildcards and epsilon matching.

Wildcards

Wildcard values are specified with an * (asterisk). For example:

m expects ("this", *)

will match any of the following:

m("this", 42)
m("this", 1.0)
m("this", null)

Epsilon matching

Epsilon matching is useful when dealing with floating point values. An epsilon match is specified with the ~ (tilde) operator:

m expects (~42.0)

will match:

m(42.0)
m(42.0001)
m(41.9999)

but will not match:

m(43.0)
m(42.1)

Repeated parameters

If you're using generated mocks, you need do nothing special to set expectations on methods that take repeated parameters. If you're using proxy mocks you will need to use the ** operator. For example, given:

def takesRepeatedParameter(x: Int, ys: String*)

you can set an expectation with:

m expects 'takesRepeatedParameter withArgs(42, **("red", "green", "blue"))

Predicate matching

More complicated argument matching can be implemented by using where to pass a predicate:

m = mockFunction[Double, Double, Unit]
m expects { where _ < _ }
m = mock[Turtle]
m expects 'setPosition where { (x: Double, y: Double) => x < y }

Return value

You can instruct a mock to return a specific value with returns or returning:

m1 returns 42
m2 expects ("this", "that") returning "the other"

If no return value is specified, functional mocks return null.asInstanceOf[R], where R is the return type (which equates to 0 for Int, 0.0 for Double etc.).

If no return value is specified, proxy mocks return null. This works correctly for most return types, but not for methods returning primitive types (Int, Double etc.), where returning null leads to a NullPointerException. So you will need to explicitly specify a return value for such methods. (This restriction may be lifted in the future.)

You can return a computed value (or throw a computed exception) with onCall, for example:

val mockIncrement = mockFunction[Int, Int]
m expects (*) onCall { x: Int => x + 1 }

Exceptions

Instead of a return value, a mock can be instructed to throw:

m expects ("this", "that") throws new RuntimeException("what's that?")

Call count

By default, mocks expect one or more calls (i.e., only fail if the function or method is never called). An exact number of calls or a range can be set with repeat:

m1 returns 42 repeat 3 to 7
m2 expects (3) repeat 10

There are various aliases for common expectations and styles:

m1 expects ("this", "that") once
m2 returns "foo" noMoreThanTwice
m3 expects (42) repeated 3 times

For a full list, see org.scalamock.Expectation.

Ordering

By default, expectations can be satisfied in any order. For example:

m expects (1)
m expects (2)
m(2)
m(1)

A specific sequence can be enforced with inSequence:

inSequence {
  m expects (1)
  m expects (2)
}
m(2) // throws ExpectationException
m(1)

Multiple sequences can be specified. As long as the calls within each sequence happen in the correct order, calls within different sequences can be interleaved. For example:

val m1 = mock[Turtle]
val m2 = mock[Turtle]

inSequence {
  m1.expects.setPosition(0.0, 0.0)
  m1.expects.penDown
  m1.expects.forward(10.0)
  m1.expects.penUp
}
inSequence {
  m2.expects.setPosition(1.0, 1.0)
  m2.expects.turn(90.0)
  m2.expects.forward(1.0)
  m2.expects.getPosition returning (2.0, 1.0)
}

m2.setPosition(1.0, 1.0)
m1.setPosition( 0.0, 0.0)
m1.penDown
m2.turn(90.0)
m1.forward(10.0)
m2.forward(1.0)
m1.penUp
expect((2.0, 1.0)) { m2.getPosition }

To specify that there is no constraint on ordering, use inAnyOrder (there is an implicit inAnyOrder at the top level). Calls to inSequence and inAnyOrder can be arbitrarily nested. For example:

m.expects.a
inSequence {
  m.expects.b
  inAnyOrder {
    m.expects.c
    inSequence {
      m.expects.d
      m.expects.e
    }
    m.expects.f
  }
  m.expects.g
}

Debugging

If faced with a difficult to debug failing expectation, consider mixing one or both of the org.scalamock.VerboseErrors or org.scalamock.CallLogging traits into your test suite:

class ExampleSpec extends FlatSpec with MockFactory with
    VerboseErrors with CallLogging ...

Using EasyMock

ScalaTest's EasyMockSugar trait provides some basic syntax sugar for EasyMock.

Using the EasyMock API directly, you create a mock with:

val mockCollaborator = createMock(classOf[Collaborator])

With this trait, you can shorten that to:

val mockCollaborator = mock[Collaborator]

After creating mocks, you set expectations on them, using syntax like this:

mockCollaborator.documentAdded("Document")
mockCollaborator.documentChanged("Document")
expectLastCall().times(3)

If you wish to highlight which statements are setting expectations on the mock (versus which ones are actually using the mock), you can place them in an expecting clause, provided by this trait, like this:

expecting {
  mockCollaborator.documentAdded("Document")
  mockCollaborator.documentChanged("Document")
  lastCall.times(3)
}

Using an expecting clause is optional, because it does nothing but visually indicate which statements are setting expectations on mocks. (Note: this trait also provides the lastCall method, which just calls expectLastCall.)

Once you've set expectations on the mock objects, you must invoke replay on the mocks to indicate you are done setting expectations, and will start using the mock. After using the mock, you must invoke verify to check to make sure the mock was used in accordance with the expectations you set on it. Here's how that looks when you use the EasyMock API directly:

replay(mockCollaborator)
classUnderTest.addDocument("Document", new Array[Byte](0))
classUnderTest.addDocument("Document", new Array[Byte](0))
classUnderTest.addDocument("Document", new Array[Byte](0))
classUnderTest.addDocument("Document", new Array[Byte](0))
verify(mockCollaborator)

This trait enables you to use the following, more declarative syntax instead:

whenExecuting(mockCollaborator) {
  classUnderTest.addDocument("Document", new Array[Byte](0))
  classUnderTest.addDocument("Document", new Array[Byte](0))
  classUnderTest.addDocument("Document", new Array[Byte](0))
  classUnderTest.addDocument("Document", new Array[Byte](0))
}

The whenExecuting method will pass the mockCollaborator to replay, execute the passed function (your code that uses the mock), and call verify, passing in the mockCollaborator. If you want to use multiple mocks, you can pass multiple mocks to whenExecuting.

To summarize, here's what a typical test using EasyMockSugar looks like:

val mockCollaborator = mock[Collaborator]

expecting { mockCollaborator.documentAdded("Document") mockCollaborator.documentChanged("Document") lastCall.times(3) }
whenExecuting(mockCollaborator) { classUnderTest.addDocument("Document", new Array[Byte](0)) classUnderTest.addDocument("Document", new Array[Byte](0)) classUnderTest.addDocument("Document", new Array[Byte](0)) classUnderTest.addDocument("Document", new Array[Byte](0)) }

An alternative approach is to place your mock objects in a MockObjects holder object referenced from an implicit val, then use the overloaded variant of whenExecuting that takes an implicit MockObjects parameter. Here's how that would look:

implicit val mocks = MockObjects(mock[Collaborator])

expecting { mockCollaborator.documentAdded("Document") mockCollaborator.documentChanged("Document") lastCall.times(3) }
whenExecuting { classUnderTest.addDocument("Document", new Array[Byte](0)) classUnderTest.addDocument("Document", new Array[Byte](0)) classUnderTest.addDocument("Document", new Array[Byte](0)) classUnderTest.addDocument("Document", new Array[Byte](0)) }

Using JMock

ScalaTest's JMockCycle class, which wraps and manages the lifecycle of a single org.jmock.Mockery context object, provides some basic syntax sugar for using JMock in Scala.

Using the JMock API directly, you first need a Mockery context object:

val context = new Mockery

JMockCycle uses jMock's ClassImposterizer to support mocking of classes, so the following line would also be needed if you wanted that functionality as well:

context.setImposteriser(ClassImposteriser.INSTANCE)

When using this class, you would instead create an instance of this class (which will create and wrap a Mockery object) and import its members, like this:

val cycle = new JMockCycle
import cycle._

Using the JMock API directly, you would create a mock object like this:

val mockCollaborator = context.mock(classOf[Collaborator])

Having imported the members of an instance of this class, you can shorten that to:

val mockCollaborator = mock[Collaborator]

After creating mocks, you set expectations on them, using syntax like this:

context.checking(
  new Expectations() {
    oneOf (mockCollaborator).documentAdded("Document")
    exactly(3).of (mockCollaborator).documentChanged("Document")
   }
 )

Having imported the members of an instance of this class, you can shorten this step to:

expecting { e => import e._
  oneOf (mockCollaborator).documentAdded("Document")
  exactly(3).of (mockCollaborator).documentChanged("Document")
}

The expecting method will create a new Expectations object, pass it into the function you provide, which sets the expectations. After the function returns, the expecting method will pass the Expectations object to the checking method of its internal Mockery context.

The expecting method passes an instance of class org.scalatest.mock.JMockExpectations to the function you pass into expectations. JMockExpectations extends org.jmock.Expectations and adds several overloaded withArg methods. These withArg methods simply invoke corresponding with methods on themselves. Because with is a keyword in Scala, to invoke these directly you must surround them in back ticks, like this:

oneOf (mockCollaborator).documentAdded(`with`("Document"))

By importing the members of the passed JMockExpectations object, you can instead call withArg with no back ticks needed:

oneOf (mockCollaborator).documentAdded(withArg("Document"))

Once you've set expectations on the mock objects, when using the JMock API directly, you use the mock, then invoke assertIsSatisfied on the Mockery context to make sure the mock was used in accordance with the expectations you set on it. Here's how that looks:

classUnderTest.addDocument("Document", new Array[Byte](0))
classUnderTest.addDocument("Document", new Array[Byte](0))
classUnderTest.addDocument("Document", new Array[Byte](0))
classUnderTest.addDocument("Document", new Array[Byte](0))
context.assertIsSatisfied()

This class enables you to use the following, more declarative syntax instead:

whenExecuting {
  classUnderTest.addDocument("Document", new Array[Byte](0))
  classUnderTest.addDocument("Document", new Array[Byte](0))
  classUnderTest.addDocument("Document", new Array[Byte](0))
  classUnderTest.addDocument("Document", new Array[Byte](0))
}

The whenExecuting method will execute the passed function, then invoke assertIsSatisfied on its internal Mockery context object.

To summarize, here's what a typical test using JMockCycle looks like:

val cycle = new JMockCycle
import cycle._

val mockCollaborator = mock[Collaborator]
expecting { e => import e._ oneOf (mockCollaborator).documentAdded("Document") exactly(3).of (mockCollaborator).documentChanged("Document") }
whenExecuting { classUnderTest.addDocument("Document", new Array[Byte](0)) classUnderTest.addDocument("Document", new Array[Byte](0)) classUnderTest.addDocument("Document", new Array[Byte](0)) classUnderTest.addDocument("Document", new Array[Byte](0)) }

ScalaTest also provides a JMockCycleFixture trait, which will pass a new JMockCycle into each test that needs one.

Using Mockito

ScalaTest's MockitoSugar trait provides some basic syntax sugar for Mockito.

Using the Mockito API directly, you create a mock with:

val mockCollaborator = mock(classOf[Collaborator])

Using this trait, you can shorten that to:

val mockCollaborator = mock[Collaborator]

Here is how the example used in the previous EasyMock and JMock sections would look with Mockito and MockitoSugar:

// First, create the mock object
val mockCollaborator = mock[Collaborator]

// Create the class under test and pass the mock to it
classUnderTest = new ClassUnderTest
classUnderTest.addListener(mock)

// Use the class under test
classUnderTest.addDocument("Document", new Array[Byte](0))
classUnderTest.addDocument("Document", new Array[Byte](0))
classUnderTest.addDocument("Document", new Array[Byte](0))
classUnderTest.addDocument("Document", new Array[Byte](0))

// Then verify the class under test used the mock object as expected
verify(mockCollaborator).documentAdded("Document")
verify(mockCollaborator, times(3)).documentChanged("Document")

Next, learn about property-based testing.

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-2013 Artima, Inc. All Rights Reserved.

artima