【问题标题】:Scala mocking trait that is extended by another trait由另一个特征扩展的 Scala 模拟特征
【发布时间】:2017-12-21 01:15:44
【问题描述】:

我正在尝试测试

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

我要做的就是确保“s.name()”方法被调用一次,方法是模拟一个 s 的实例,它是一个系统。

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() 时返回一个模拟 System,以便我可以验证系统只调用 s.name() 一次。如果它是 Name trait 中的 name() 方法的参数,我可以轻松地模拟这个 System,所以我想我不知道如何在调用该方法时“注入”要使用的 mockSystem 而不是真实系统。

【问题讨论】:

    标签: scala mockito traits scalatest


    【解决方案1】:

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

    您似乎在Helper 及其继承中使用了类似蛋糕模式的东西。如果是这样,您可以使用类而不是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 内的所有调用执行此操作,否则测试将无法工作。

    【讨论】:

      猜你喜欢
      • 2014-02-18
      • 2015-06-03
      • 1970-01-01
      • 1970-01-01
      • 2019-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-11
      相关资源
      最近更新 更多