Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala-Mock是一种通过名称参数接收调用的方法_Scala_Unit Testing_Mockito_Named Parameters - Fatal编程技术网

Scala-Mock是一种通过名称参数接收调用的方法

Scala-Mock是一种通过名称参数接收调用的方法,scala,unit-testing,mockito,named-parameters,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.com

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

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
如您所见,我使用这个参数实际上是作为一个函数发送给这个方法(有点像供应商)。我不明白为什么嘲笑不起作用。只要我不能控制client.compute(..)返回什么,我就不能编写单元测试


非常感谢您的帮助。

模拟的问题与以下事实有关:您没有在
客户端
特征中明确声明
计算
方法的返回类型,并且由于没有实体,因此推断为
单位

因此,当您试图用

client.compute(getValue) returns "result"
您没有定义该方法的行为。
必须显式声明公共方法的返回类型

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

trait Client { 
    def compute(valueFunction => Function0[String]): String
}
电话被转换成这样的东西

client.compute(() => { getValue() })
或者更明确地说:

client.compute(new Funciton0[String]{ def apply():String = { getValue() }})
因此,Mockito
返回
不起作用,因为在
compute
的两个调用中,传递的参数实际上是两个不同的
Function0
对象。而且因为
函数0
没有覆盖
equals
,所以它们不匹配

解决这个问题的技巧是首先将
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
的其他方法,并且您想要模拟该调用,我不知道如何帮助您在不重写至少部分代码的情况下保留准确的语义。可能我能想到的最简单的事情就是在签名中显式地使用
function0
,然后使用
匹配器

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

实际上,我声明了返回类型。我的错,我不小心没把它写在我的问题上。Will editSo,也许值得检查完美。谢谢!这里还有一个例子:我实际上是从Java类调用client.compute。所以它看起来是这样的:client.compute(()->getValue)。这样模仿就不会像预期的那样再次起作用。有什么线索吗?@AmitPe'er,你的意思是你实际测试的不是
client.compute
,而是Java中调用
client.compute
的其他方法,你想模拟这个调用吗?如果是这样的话,我不知道如何帮助你保留准确的语义。请参阅答案中的我的更新,了解一些可能对您有帮助或没有帮助的想法。谢谢-看一看。假设我想做同样的事情,但是从Scala类而不是java?它会不会更简单?@AmitPe'er,除非你有非常罕见的代码,否则我认为从Scala调用它不会让事情变得更简单。问题仍然是,您需要向模拟调用传递与实际调用完全相同的参数。而且很可能您没有将实际调用中使用的值保存到某个字段,以便在模拟调用中重复使用。因此,唯一的选择似乎是使用
参数匹配器。任何
,如果不将签名从
按名称调用
显式转换为
Function0
,我都无法使其工作。