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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With