User Guide - Advanced topics

Advanced topics

If you are looking for plain old scalamock examples, please refer to ScalaMock section.

ScalaMock 7

Mocking 0-parameter method

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

val fooMock = mock[Foo]

fooMock.bar().returns(0)
fooMock.buz.returns(0)

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)).returns(_ => "")
(fooMock.overloaded(_: String)).returns(_ => "")
fooMock.overloaded[Double].returns(_ => "")

Also you can inline it to use later on:


inline def overloadedInt = fooMock.overloaded(_: Int)

overloadedInt.returns(_ => "")
overloadedInt.times

Polymorphic methods

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


val fooMock = mock[Foo]

fooMock.polymorphic[Int].returns:
  case List(1, 2, 3) => ""
  case _ => "0"

// also you can specify argument types if compiler somehow can't resolve a method
(fooMock.polymorphic[Int](_: List[Int])).returns:
  case List(1, 2, 3) => ""
  case _ => "0"

Curried methods

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


val fooMock = mock[Foo]

(fooMock.curried(_: Int)(_: Double)).returns:
  case (10, 1.23) => ""

// this also can be inlined and used

inline def curried = fooMock.curried(_: Int)(_: Double)

curried.returns(_ => "")

Methods with using parameters

class Codec()

trait Memcached:
  def get(key: String)(using Codec): Option[Int]

val memcachedMock = mock[Memcached]

given Codec = new Codec
(memcachedMock.get(_ : String)(using _: Codec)).returns((x, y) => Some(123))

// this also can be inlined and used

inline def withUsingParams = memcachedMock.get(_ : String)(using _: Codec)

withUsingParams.returns(_ => Some(123))

Repeated parameters

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

trait Foo:
  def takesRepeatedParameter(x: Int, ys: String*): Unit
  def takesRepeatedParamCurried(x: Int*)(y: String*): Unit

you can set an expectation with:

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

(fooMock.takesRepeatedParamCurried((_: Seq[Int])*)((_: Seq[String])*))
  .returns((seq1, seq2) => ())

// this also can be inlined and used later on

inline def multipleRepeatedCurried = fooMock
  .takesRepeatedParamCurried((_: Seq[Int])*)((_: Seq[String])*)

multipleRepeatedCurried.returns((seq1, seq2) => ())

ScalaMock

Mocking 0-parameter method

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

val fooMock = mock[Foo]

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

Mocking overloaded, curried and polymorphic methods

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

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).returns("")
(fooMock.overloaded(_: String)).expects("foo").returns("")
fooMock.overloaded[Double].expects(1.23).returns("")

Polymorphic methods

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


val fooMock = mock[Foo]

fooMock.polymorphic[Int].expects(List(1, 2, 3)).returns("")

// also you can specify argument types if compiler somehow can't resolve a method
(fooMock.polymorphic[Int](_: List[Int])).expects(List(1, 2, 3)).returns("") 

Curried methods

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


val fooMock = mock[Foo]

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

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)(using Codec): Option[Int]

val memcachedMock = mock[Memcached]

given Codec = new Codec
(memcachedMock.get(_ : String)(using _: Codec)).expects("some_key", *).returning(Some(123))

Repeated parameters

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

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

you can set an expectation with:

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

Returning values (onCall)

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.

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

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)).returns(()).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)).returns(()).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().returns(()).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()