使用按名称传递的参数模拟函数

时间:2016-03-11 19:37:35

标签: scala unit-testing junit mocking mockito

我的实际用例是涉及finagle FuturePool的单元测试代码:我想确保实际调用了FuturePool.apply,以便在正确的池实例中执行任务。

然而,我遇到的问题似乎更通用,所以我将在一个抽象的例子中说明它,与finagle或future无关。

假设我有这两个类:

    class Foo {
      def apply(f: => String) = f
    }

    class Bar(val foo: Foo) {
      def doit(f: => String) = foo(f)
    }

Bar有一个Foo的实例,它知道如何运行函数,我想测试它实际上是用它来执行的:

    describe("Bar") {
      it("should use the right foo") {
        val foo = mock[Foo]
        when(foo.apply(any)).thenAnswer( new Answer[String] {
          def answer(invocation: InvocationOnMock): String =
            invocation.getArgumentAt(0, classOf[Function0[String]]).apply()
        })
        new Bar(foo).doit("foo") should equal("foo")
      }
    }

这不起作用:.doit显然是返回null,因为mockito没有意识到它被嘲笑了。在这种情况下,any似乎与Function0不匹配(将其替换为any[Function0[String]]也无济于事。

我也尝试了另一种方式:

it("should Foo!") {
    val foo = Mockito.spy(new Foo)
    new Bar(foo).doit("foo") should equal("foo")
    verify(foo).apply(any)
  }

这也行不通,有点证实了我怀疑any在这种情况下没有工作:

Argument(s) are different! Wanted:
foo$1.apply(
    ($anonfun$apply$mcV$sp$7) <function0>
);
Actual invocation has different arguments:
foo$1.apply(
    ($anonfun$apply$mcV$sp$6) <function0>
);

有关解决这个问题的好方法吗?

1 个答案:

答案 0 :(得分:0)

此签名:

def apply(f: => String)

被称为“按名称调用”,它传递表达式而不是计算表达式。这对于Scala非常具体,并且没有得到Mockito的支持。

有很多解决方法:

one by Eric看起来最简单,你可能想要什么。