简体   繁体   中英

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

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

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM