由另一个特征扩展的 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
内的所有调用执行此操作,否则测试将无法进行。
我正在尝试测试
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
内的所有调用执行此操作,否则测试将无法进行。