scala ScalaMock:如何模拟/存根方法以在每次调用时返回不同的值?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34162431/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 07:51:11  来源:igfitidea点击:

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

scalatestingmockingscalamock

提问by Eyal Roth

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

使用 ScalaMock,我想模拟/存根类方法,以便每次调用返回不同的值(调用顺序很重要)。

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

我可以用mock和实现这一点expects,但这将迫使我验证这些调用。

Can I do this with a stub?

我可以用 做这个stub吗?

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

另外,我怎么能说“第一次返回 X,然后总是返回 Y”(包括mockstub)?

回答by Akzok

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.

使用 .noMoreThanOnce() 而不是 .once() 很重要,否则会导致调用被验证。还有一个 .noMoreThanTwice() 方法,但我认为没有 .noMoreThanNTimes() 或任何等效方法。



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

下面是如何为模拟和存根做“第一次返回 X,然后总是返回 Y”:

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

回答by botchniaque

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 onCallmethod - it takes a closure of your function. By default it will serve only the first call, so make sure to add anyNumberOfTimesor some repreted(...).

对我来说,编写不验证调用并且返回值取决于输入的模拟的最佳方法是使用onCall方法 - 它需要关闭您的函数。默认情况下,它只会服务于第一次调用,因此请确保添加anyNumberOfTimes或一些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 Xand each consecutive Y.

现在第一次调用fooMock.someValue(...)将返回X并且每个连续的Y.