Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ScalaMock: How to mock/stub a method to return different values per call?

Using ScalaMock, I want to mock/stub a class method so it will return a different value per call (order of calls matters).

I can achieve this with mock and expects, but that will force me to verify those calls.

Can I do this with a stub?

Also, how can I say something like "first time return X, and then always return Y" (both with mock and stub)?

like image 901
Eyal Roth Avatar asked Dec 08 '15 17:12

Eyal Roth


2 Answers

Yes, this can be done, although the syntax is a little unintuitive:

    trait Foo { def getInt: Int }
    val fooStub = stub[Foo]

    (fooStub.getInt _).when().returns(1).noMoreThanOnce()
    (fooStub.getInt _).when().returns(2).noMoreThanOnce()
    (fooStub.getInt _).when().returns(3)
    (fooStub.getInt _).when().returns(4)

    assert(fooStub.getInt == 1)
    assert(fooStub.getInt == 2)
    assert(fooStub.getInt == 3)
    // Note that it's fine that we don't call it a fourth time - calls are not verified.

It's important to use .noMoreThanOnce() rather than.once(), otherwise you cause the calls to be verified. There is also a .noMoreThanTwice() method, but I don't think there is a .noMoreThanNTimes() or any equivalent.


Here is how to do "first time return X, and then always return Y" for mocks and stubs:

    trait Bar { def getString: String }
    val barMock = mock[Bar]

    (barMock.getString _).expects().returning("X")
    (barMock.getString _).expects().returning("Y").anyNumberOfTimes()

    assert(barMock.getString == "X")
    assert(barMock.getString == "Y")
    assert(barMock.getString == "Y")

    val barStub = stub[Bar]

    (barStub.getString _).when().returns("x").noMoreThanOnce()
    (barStub.getString _).when().returns("y")

    assert(barStub.getString == "x")
    assert(barStub.getString == "y")
    assert(barStub.getString == "y")
like image 144
Akzok Avatar answered Nov 16 '22 02:11

Akzok


For me the best way to write a mock which does not verify calls and where returning value depends on the input is to use onCall method - it takes a closure of your function. By default it will serve only the first call, so make sure to add anyNumberOfTimes or some repreted(...).

import org.scalamock.scalatest.MockFactory

trait Foo {
  def getSomeValue(param1: Any, param2: Any): String
}

class Test extends MockFactory {
  val fooMock = stub[Foo]

  val it = Iterator.single("X") ++ Iterator.continually("Y")

  (fooMock.getSomeValue _)
    .expects(*, *)
    .onCall((p1, p2) => it.next())
    .anyNumberOfTimes
}

Now the first call to fooMock.someValue(...) will return X and each consecutive Y.

like image 26
botchniaque Avatar answered Nov 16 '22 02:11

botchniaque