【问题标题】:How to set up a ScalaMock once for repeated method invocations?如何为重复的方法调用设置一次 ScalaMock?
【发布时间】:2017-01-27 22:58:53
【问题描述】:

我想在 Scala 中设置一个测试,创建一个模拟配置来提供某些值。我正在使用 ScalaTest 3.0.1、ScalaMock 3.4.2、 和类型安全的 1.3.1。目标是在运行测试之前模拟配置的值。文档位于 http://www.scalatest.org/user_guide/testing_with_mock_objectshttp://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() 一样。应该如何编码,以便可以模拟一次该方法并且 反复调用?为什么第二次尝试失败?有没有办法重置模拟以便重复使用?

【问题讨论】:

    标签: scala scalatest scalamock


    【解决方案1】:

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

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

    【讨论】:

    • 我应用了第一种技术(OneInstancePerTest),并且更喜欢这个。我在其他地方看过文档,但这个解释更清楚。编辑以提供示例...
    【解决方案2】:

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

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

    这很容易,因为您的测试根本不会改变。您只是将逻辑从“全局本地”变量移动到单个测试的本地范围内。

    【讨论】:

    • 哦,有趣。我尝试在 before 块中重新创建它,但与我在问题中的尝试 2 有相同的错误。
    • 我喜欢你的回答。编辑以在设置周围添加一些上下文。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-19
    • 1970-01-01
    相关资源
    最近更新 更多