User Guide - Advanced topics

Advanced topics

Mocking overloaded, curried and polymorphic methods

Overloaded, curried and polymorphic methods can be mocked by specifying either argument types or type parameters.

Example 1 - Overloaded methods

trait Foo {
  def overloaded(x: Int): String
  def overloaded(x: String): String
  def overloaded[T](x: T): String
}

val fooMock = mock[Foo]

(fooMock.overloaded(_: Int)).expects(10)
(fooMock.overloaded(_: String)).expects("foo")
(fooMock.overloaded[Double] _).expects(1.23)

You may also prefer to use this slightly different syntax:

(fooMock.overloaded _: Int => String).expects(10)  // or
(fooMock.overloaded _: Int => String) expects (10) // or
(fooMock.overloaded(_: Int)) expects (10)

Example 2 - Polymorphic methods

trait Foo {
  def polymorphic[T](x: List[T]): String
}

val fooMock = mock[Foo]

(fooMock.polymorphic(_: List[Int])).expects(List(1, 2, 3))            // or
(fooMock.polymorphic[Int] _).expects(List(1, 2, 3))                   // or
(fooMock.polymorphic _ : List[Int] => String).expects(List(1, 2, 3))

Example 3 - Curried methods

trait Foo {
  def curried(x: Int)(y: Double): String
}

val fooMock = mock[Foo]

(fooMock.curried(_: Int)(_: Double)).expects(10, 1.23)

Example 4 - Methods with implicit parameters

This case is very similar to curried methods. All you need to do is to help the Scala compiler know that memcachedMock.get _ should be converted to MockFunction2. For example:

class Codec()

trait Memcached {
  def get(key: String)(implicit codec: Codec): Option[Int]
}

val memcachedMock = mock[Memcached]

implicit val codec = new Codec
(memcachedMock.get(_ : String)(_ : Codec)).expects("some_key", *).returning(Some(123))

Example 5 - Repeated parameters

Repeated parameters are represented as a Seq. For example, given:

trait Foo {
  def takesRepeatedParameter(x: Int, ys: String*)
}

you can set an expectation with:

(fooMock.takesRepeatedParameter _).expects(42, Seq("red", "green", "blue"))

Returning values (onCall)

By default mocks and stubs return null. You can return predefined value using the returning() method, or in the case of stubs, returns(). When the returned value depends on function arguments, you can return the computed value (or throw a computed exception) with onCall(). For example:

trait Foo {
    def increment(a: Int): Int
}

val fooMock = mock[Foo]

(fooMock.increment _) expects(12) returning(13)
fooMock.increment(12) shouldBe 13 

(fooMock.increment _) expects(*) onCall { arg: Int => arg + 1}
fooMock.increment(100) shouldBe 101

(fooMock.increment _) expects(*) onCall { arg: Int => throw new RuntimeException("message") }
intercept[RuntimeException] { fooMock.increment(0) }
val mockIncrement = mockFunction[Int, Int]
mockIncrement expects (*) onCall { arg: Int => arg + 1 }
mockIncrement(10) shouldBe  11 

Call count

By default, mocks expect exactly one call while stubs allow any number of calls. For stubs, an exact number of calls can be specified in the verification phase. For mocks, alternative constraints can be set with repeat():

mockedFunction.expects(42).returns(42).repeat(3 to 7)
mockedFunction expects (3) repeat 10

There are various aliases for common expectations and styles:

val mockedFunction1 = mockFunction[Int, String]
val mockedFunction2 = mockFunction[Int, String]
val mockedFunction3 = mockFunction[Int, String]
val mockedFunction4 = mockFunction[Int, String]
val mockedFunction5 = mockFunction[Int, String]

mockedFunction1.expects(1).returning("foo").once
mockedFunction2.expects(2).returning("foo").noMoreThanTwice
mockedFunction3.expects(3).returning("foo").repeated(3).times
mockedFunction4.expects(4).returning("foo").repeat(1 to 2)
mockedFunction5.expects(5).returning("foo").repeat(2)
mockedFunction5.expects(6).returning("foo").never()

mockedFunction1(1)

//mockedFunction2(2) - not called

mockedFunction3(3)
mockedFunction3(3)
mockedFunction3(3)

mockedFunction4(4)
mockedFunction4(4)

mockedFunction5(5)
mockedFunction5(5)

//mockedFunction6(6) - not called

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

Exceptions

Instead of a return value, mocks and stubs can be instructed to throw an exception. This can be achieved either by throwing exception in the onCall handler or by using the throws method.

Example 1 - throws method

trait Foo {
  def increment(a: Int): Int
}

val fooMock = mock[Foo]

(fooMock.increment _) expects (5) throws new RuntimeException("message")

intercept[RuntimeException] { fooMock.increment(5) }

Example 2 - throwing from the onCall handler

(fooMock.increment _) expects(*) onCall { arg: Int => 
  if (arg == 0) 
      throw new RuntimeException("message") 
  else
      arg + 1
}

intercept[RuntimeException] { fooMock.increment(0) }

Partial Functions

Example 1

val m = mockFunction[Int, String]
val mp = new PartialFunction[Int, String] {
  def isDefinedAt(x: Int) = true
  def apply(v1: Int) = m(v1)
}

m expects 42 returning "foo" once()

mp(42) shouldBe "foo"

Raw types

Example 1

Try this solution if you get this error:

error: could not find implicit value for evidence parameter of type org.scalamock.Defaultable[SomeType]

e.g., such as the following example for Enumeration and Map

public interface RawTypeInterface {
    java.util.Enumeration foo();
    java.util.Map bar();
}
"mocking a java method with raw type" should "work" in {
  implicit val d = new Defaultable[java.util.Enumeration[_]] {
    override val default = null
  }
  implicit val d2 = new Defaultable[java.util.Map[_, _]] {
    override val default = null
  }
  
  val mockedRaw = mock[RawTypeInterface]
}

Log Calls

Example 1

inAnyOrderWithLogging { // or inSequenceWithLogging
  someMock.foo _ expects() returning 42 anyNumberOfTimes()
}

This will print all invocations of call handlers and verifiers with the corresponding calls.

Argument Capture

(since ScalaMock 4.2.0) Using the Capture feature in org.scalamock.matchers.ArgCapture, it is easy and convenient to allow wildcard matches but assert on the results later on. It is possible to store either a single value in a CaptureOne, or a Seq or values with a CaptureAll. Note that the call to .value will throw if nothing was captured. Also, the CaptureOne will only keep the last value captured, should it be invoked multiple times.

  "ScalaMock" can "capture the arguments of mocks - capture one" in {
    val m = mock[TestTrait]
    val c1 = CaptureOne[Int]()

    m.oneParam _ expects capture(c1) once()
    m.oneParam(42)
    c1.value should be (42)
  }

  "ScalaMock" can "capture the arguments of mocks - capture all" in {
    val m = mock[TestTrait]
    val c = CaptureAll[Int]()

    m.oneParam _ expects capture(c) repeat 3
    m.oneParam(99)
    m.oneParam(17)
    m.oneParam(583)
    c.value should be (583)
    c.values should be (Seq(99, 17, 583))
  }

Using ScalaMock without ScalaTest/Specs2

You just need to implement your own subtype of MockFactoryBase. Technically you can adapt ScalaMock to be used inside JUnit, µTest, etc this way, or any other framework really.

import org.scalamock.MockFactoryBase
import org.scalamock.clazz.Mock

object NoScalaTestExample extends Mock {
  trait Cat {
    def meow(): Unit
    def isHungry: Boolean
  }

  class MyMockFactoryBase extends MockFactoryBase {
    override type ExpectationException = Exception
    override protected def newExpectationException(message: String, methodName: Option[Symbol]): Exception =
      throw new Exception(s"$message, $methodName")

    def verifyAll(): Unit = withExpectations(() => ())
  }

  implicit var mc: MyMockFactoryBase = _
  var cat: Cat = _

  def main(args: Array[String]): Unit = {
    // given: I have a mock context
    mc = new MyMockFactoryBase
    // and am mocking a cat
    cat = mc.mock[Cat]
    // and the cat meows
    cat.meow _ expects() once()
    // and the cat is always hungry
    cat.isHungry _ expects() returning true anyNumberOfTimes()

    // then the cat needs feeding
    assert(cat.isHungry)

    // and the mock verifies
    mc.verifyAll()
  }
}

Mocking 0-parameter function and parameterless function

trait Foo {
  def bar(): Int
  def buz: Int
}

val fooMock = mock[Foo]

(() => fooMock.bar()).expects(10)
(() => fooMock.buz).expects(10)