Scala - 模拟接收按名称调用参数的方法

时间:2018-01-17 18:17:22

标签: scala unit-testing mockito named-parameters

假设我有以下特征,一个方法接收一个按名称调用的参数:

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"

问题是,当调用mocked方法时,它不会返回预期值:

client.compute(getValue) mustEqual "result" // fails. returns null

正如您所看到的,我实际上将此参数用作我发送给方法的函数(有点像供应商)。我不明白为什么Mocking不起作用。只要我无法控制client.compute(..)返回的内容,我就无法编写单元测试。

非常感谢帮助。

2 个答案:

答案 0 :(得分:2)

按名称调用参数实际上编译成如下:

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

答案 1 :(得分:0)

模拟的问题与以下事实有关:您没有明确声明mp特征中compute方法的返回类型,并且假设没有正文,则推断成为Client

因此,当您尝试使用

定义模拟行为时
Unit

您没有定义该方法的行为。 您必须显式声明公共方法的返回类型