[英]Scala - Mock a method that receives a call-by-name parameter
假设我具有以下特征,并且具有一个接收按名称调用参数的方法:
trait Client {
def compute(value: => String): String
}
另外,假设我具有以下功能:
final def getValue: String = {
"value"
}
现在让我们说我正在尝试通过以下方式使用Mockito(org.specs2.mock.Mockito)模拟此类:
val client: Client = mock[Client]
client.compute(getValue) returns "result"
问题在于,当调用模拟方法时,它不会返回预期值:
client.compute(getValue) mustEqual "result" // fails. returns null
如您所见,我实际上将此参数用作发送给该方法的函数(有点像Supplier)。 我不明白为什么模拟不起作用。 只要我无法控制client.compute(..)返回的值,就无法编写单元测试。
非常感谢您的帮助。
按名称呼叫参数实际上被编译成如下形式:
trait Client {
def compute(valueFunction => Function0[String]): String
}
通话被转换成这样
client.compute(() => { getValue() })
或更明确地说:
client.compute(new Funciton0[String]{ def apply():String = { getValue() }})
所以Mockito returns
不起作用,因为在两次调用compute
中,传递的参数实际上是两个不同的Function0
对象。 并且因为equals
不会被Function0
覆盖,所以它们不匹配。
解决此问题的技巧是首先将您的getValue
方法显式转换为本地Function0[String]
变量。 这似乎足以使两个client.compute
调用生成相同的对象,以使Mockito正常工作。 因此,您可以尝试使用以下代码:
import org.specs2._
import org.specs2.mock.Mockito
class Specs2Test extends Specification with Mockito {
override def is =
s2"""
this works $good
this doesn't $bad
"""
final def getValue: String = {
"value"
}
def good = {
val client: Client = mock[Client]
val f: Function0[String] = getValue _
client.compute(f()) returns "result"
client.compute(f()) mustEqual "result"
}
def bad = {
val client: Client = mock[Client]
client.compute(getValue) returns "result"
client.compute(getValue) mustEqual "result" // fails. returns null
}
}
更新
如果您实际测试的不是client.compute
而是Java中调用client.compute
其他方法,并且您想模拟该调用,那么我不知道如何在不重写至少某些代码的情况下帮助您保留确切的语义。 我可能想到的最简单的事情是在签名中显式使用Funciton0
,然后使用Matchers.any
如
trait Client {
def compute(value: () => String): String
}
接着
def usingMatchAny = {
val client: Client = mock[Client]
client.compute(ArgumentMatchers.any()) returns "result"
// actually here you call the method that uses client.compute call
client.compute(getValue _) mustEqual "result"
}
Mock的问题与以下事实有关:您没有在Client
特性中显式声明compute
方法的返回类型,并且由于没有主体,因此将其推断为Unit
。
因此,当您尝试定义模拟行为时,
client.compute(getValue) returns "result"
您没有为该方法定义行为。 您必须显式声明公共方法的返回类型
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.