如何为重复的方法调用设置一次 ScalaMock?

How to set up a ScalaMock once for repeated method invocations?

我想在 Scala 中设置一个测试,创建一个模拟配置以提供某些值。我正在使用 ScalaTest 3.0.1,ScalaMock 3.4.2, 和类型安全 1.3.1。目标是在 运行 测试之前模拟配置的值。文档位于 http://www.scalatest.org/user_guide/testing_with_mock_objects and http://scalamock.org/user-guide/features/ 似乎提供 几个选项。首先,这是一些目标代码:

import com.typesafe.config.Config
class Sample(config: Config) {
    private val aValue = config.getDouble("aValue")
}

似乎应该可以一次设置所有内容,或者在每次测试之前设置所有内容。此尝试失败:

class SampleSpec extends FlatSpec with MockFactory with BeforeAndAfterAll {

  private val mockConfig = mock[Config]

  override def beforeAll {
    (mockConfig.getDouble _).expects("aValue").returning(1.0).anyNumberOfTimes()
  }

  "testOne" should "return 1" in {
    new Sample(mockConfig)
  }

  "testTwo" should "return 1" in {
    new Sample(mockConfig)
  }

}

第一个测试成功但夹具中的第二个测试失败,并产生此错误:

Unexpected call: <mock-1> Config.getDouble(aValue)

Expected:
inAnyOrder {

}

Actual:
  <mock-1> Config.getDouble(aValue)
ScalaTestFailureLocation: scala.Option at (Option.scala:120)
org.scalatest.exceptions.TestFailedException: Unexpected call: <mock-1> Config.getDouble(aValue)

Expected:
inAnyOrder {

}

这是另一种方法:

class SampleSpec extends FlatSpec with MockFactory with BeforeAndAfter {

  private val mockConfig = mock[Config]

  before {
    (mockConfig.getDouble _).expects("aValue").returning(1.0)
  }

  "testOne" should "return 1" in {
    new Sample(mockConfig)
  }

  "testTwo" should "return 1" in {
    new Sample(mockConfig)
  }

}

它产生这个异常:

An exception or error caused a run to abort: assertion failed: Null expectation context - missing withExpectations?
java.lang.AssertionError: assertion failed: Null expectation context - missing withExpectations?

为什么第一次尝试失败?该测试指定 getDouble 可以被调用任意次数,但第二次 测试失败,就好像 anyNumberOfTimes() 没有被使用一样。这应该如何编码,以便该方法可以被模拟一次并且 反复调用?为什么第二次尝试失败?是否有重置模拟以便重复使用的方法?

每次都重新创建模拟,手动是我让它工作的唯一方法:

class SampleSpec extends FlatSpec with MockFactory {

  private def mockConfig = {
    val mocked = mock[Config]
    (mocked.getDouble _).expects("aValue").returning(1.0).anyNumberOfTimes()
    mocked
  }

  "testOne" should "return 1" in {
    new Sample(mockConfig)
  }

  "testTwo" should "return 1" in {
    new Sample(mockConfig)
  }

}

这很容易,因为您的测试根本没有改变。您只是将逻辑从 "globally local" 变量移动到单个测试的本地范围。

我还想指出它的文档页面,风格略有不同(使用特征):

http://scalamock.org/user-guide/sharing-scalatest/#fixture-contexts

例如:

class SampleSpec extends FlatSpec with OneInstancePerTest with MockFactory {

  private val mockConfig = mock[Config]

  (mockConfig.getDouble _).expects("aValue").returning(1.0).anyNumberOfTimes

  "testOne" should "return 1" in {
    new Sample(mockConfig)
  }

  "testTwo" should "return 1" in {
    new Sample(mockConfig)
  }

}