由另一个特征扩展的 Scala 模拟特征

Scala mocking trait that is extended by another trait

我正在尝试测试

trait Name extends Helper {
    def name() = {
      var s = getSystem()
      s.name()
    }
}

我想做的就是确保通过模拟 s 的实例调用一次 "s.name()" 方法,它是一个 System.

Helper 定义如下:

trait Helper {
    def getSystem() : System = {
       systemGetter.get()
    }
}

截至目前,我的 NameSpec 看起来像:

class NameSpec extends FlatSpec with Matchers with MockitoSugar {

    class NameImpl extends Name
    var toTest = new NameImpl

    val mockSystem = mock[System]

    it should "call s.name() once" in {
        when(getSystem() is invoked, return a mockSystem) 
        toTest.name()
        // Verify that mockSystem.name() happened only once
    }
}

我感到困惑的是如何在 toTest.name() 调用 getSystem() 时 return 模拟系统,以便我可以验证系统调用 s.name () 只有一次。如果它是 Name 特征中 name() 方法的参数,我可以很容易地模拟这个系统,所以我想我不知道如何 "inject" 在该方法是时使用模拟系统而不是真实系统已调用。

不幸的是,您的代码不可编译,因此显然不能充分代表您的实际情况。特别是不清楚 Helper 是如何真正获得类型 System 的对象的。我认为在实际代码中你应该模拟 systemGetter,我想它以某种方式注入到实现 Helper 特征的对象中,到 return 你的 mockSystem。但是,很难根据您提供的代码向您展示一个有效的示例。如果出于某种原因这不是您可以做的,还有更多途径。

您似乎围绕 Helper 及其继承使用了类似 Cake 模式的东西。如果是这样,您可以使用 class 而不是 NameImpl 来注入 System:

class NameWithInjectedSystem(val system: System) extends Name {
  override def getSystem(): System = system
}

it should "call s.name() once" in {
  val mockSystem = mock[System]
  val nameToTest = new NameWithInjectedSystem(mockSystem)
  val mockName = "Mock name"

  when(mockSystem.name()).thenReturn(mockName)
  val actual = nameToTest.name()
  actual should === (mockName)
  verify(mockSystem, times(1)).name()
}

最后你甚至可以模拟 nameToTest 对象本身,但这不是我建议的方式,因为它将测试绑定到比你想要的更多的实现细节:

it should "call s.name() once" in {
  val mockSystem = mock[System]
  val nameToTest = mock[NameImpl]
  when(nameToTest.getSystem()).thenReturn(mockSystem)
  when(nameToTest.name()).thenCallRealMethod()
  val mockName = "Mock name"
  when(mockSystem.name()).thenReturn(mockName)
  val actual = nameToTest.name()
  actual should ===(mockName)
  verify(mockSystem, times(1)).name()
}

请注意您必须如何为 .name() 调用调用 thenCallRealMethod,因此您应该为 name 内的所有调用执行此操作,否则测试将无法进行。