0

我在Scala中有一个函数如下

object MyService extends MyTrait {    
  def myMethod[T <% InvokableBuilder[MyClass]](builder: T): MyResponse = {
  //do something
  }
}

我正在尝试使用 mockito 来模拟这个函数,如下所示

val mockService = mock[MyTrait]

doReturn(info).when(mockService).myMethod(any())

尽管函数中只有一个参数,但出现以下错误

org.mockito.exceptions.misusing.InvalidUseOfMatchersException:参数匹配器的使用无效![信息] 预计 2 个匹配器,1 个记录:

4

2 回答 2

1

你的问题是:scala不是java。

您的隐含假设是:“那里的小 scala 方法在 Java 中被翻译成类似的东西;因此我可以简单地使用 mockito 来处理它”。

错误的。您正在这里创建一个 scala对象定义;如果我没记错的话;scala 中的对象...在 Java中转换为静态(例如,请参见此处)。

因此,乍一看,您可能需要分别求助于 PowerMock(ito)。JMockit 以模拟那些静态元素。(以及我通常的警告:不要使用 PowerMock;因为模拟静态的东西是个主意)。正如 Philipp M 在他的评论中指出的那样:嘲笑静态真的被认为是不好的做法。您应该在这里研究嘲笑事物的“特征”方面。

所以真正的答案是:你必须知道你在做什么。Mockito 是为java编写的。您不能仅仅假设您在 scala 中写下的任何“看起来”像 Java 的东西都可以轻松地映射到 Mockito 正在研究的概念。

为了真正了解发生了什么;您应该首先查看 scala 编译器在您的情况下创建的类文件;检查方法签名;并自己思考:“如果我必须在 java 源代码中调用该方法,我该怎么做?” 并从那里工作。

于 2017-04-24T08:06:27.730 回答
0

我将您的// 更改为 ??? 所以它会编译,然后在解析器阶段结束时打印代码:

$scalac MyService.scala -Xprint:parser
[[syntax trees at end of                    parser]] // MyService.scala
package <empty> {
  object MyService extends MyTrait {
    def <init>() = {
      super.<init>();
      ()
    };
    def myMethod[T](builder: T)(implicit evidence$1:_root_.scala.Function1[T,InvokableBuilder[MyClass]]): MyResponse = $qmark$qmark$qmark
  }
}

如您所见,由于您的视图绑定,myMethod 有第二个参数列表。我不确定你会如何用 Mockito 来模拟它,但我建议尝试一下 ScalaMock。

注意:不推荐使用视图边界 - 我建议用隐式参数替换它们(请参阅上面的 scalac 解析器如何执行此操作)。

长的例子:

import org.scalamock.scalatest.MockFactory
import org.scalatest.FlatSpec

import scala.language.implicitConversions

class FooTest extends FlatSpec with MockFactory {

  trait MyTrait {
    def myMethod[T](builder: T)(implicit ev$1: T => InvokableBuilder[MyClass]): MyResponse
  }

  trait InvokableBuilder[T]

  class MyClass

  class MyResponse

  class Foo

  object MyService extends MyTrait {
    def myMethod[T](builder: T)(implicit ev$1: T => InvokableBuilder[MyClass]): MyResponse = {
      //do something
      ???
    }
  }

  behavior of "Foo"

  it should "foo" in {
    val x = mock[MyTrait]

    implicit val fooConvert: Foo => InvokableBuilder[MyClass] = ???
    (x.myMethod(_: Foo)).expects(*).once()
  }

}
于 2017-04-25T14:23:10.827 回答