模拟带有传递参数的函数 [英] Mocking a function with pass-by-name arguments

查看:86
本文介绍了模拟带有传递参数的函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

My actual use-case is unit testing code involving finagle FuturePool: I want to make sure, FuturePool.apply was actually invoked, so that the task was executed in the correct instance of the pool.

但是,我遇到的问题似乎更为笼统,因此我将在一个抽象示例中说明该问题,该示例与finagle或Future无关.

The problem I am running into however seems more generic, so I will illustrate it on an abstract example, not related to finagle or futures.

假设,我有以下两个类:

Suppose, I have these two classes:

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

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

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

Bar has an instance of Foo, that knows how to run functions, and I want to test that it is actually using it for execution:

    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,这是因为嘲笑未意识到它是被嘲笑的.在这种情况下,any似乎与Function0不匹配(用any[Function0[String]]替换它也无济于事.

This does not work: .doit return null, apparently, because mockito does not realize it was mocked. It seems that any is not matching Function0 in this case (replacing it with any[Function0[String]] does not help either.

我也尝试了另一种方式:

I also tried it another way:

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

这也不起作用,还可以证实我对any在这种情况下不起作用的怀疑:

This also does not work, and kinda confirms my suspicion about any not working in this case:

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>
);

是否有解决此问题的好方法?

Any ideas about a good way to get around this?

推荐答案

此签名:

def apply(f: => String)

被称为按名称调用",其中它传递一个表达式而不是一个求值表达式.这是Scala特有的,Mockito无法很好地支持.

is known as "call by name" where it passes an expression instead of an evaluated expression. This is very specific to Scala and not well supported with Mockito.

有很多解决方法:

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆