【问题标题】:Mocking a function with pass-by-name arguments使用传递名称参数模拟函数
【发布时间】:2016-03-11 19:37:35
【问题描述】:

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

然而,我遇到的问题似乎更普遍,所以我将用一个抽象的例子来说明它,与 finagle 或期货无关。

假设,我有这两个类:

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

关于解决此问题的好方法有什么想法吗?

【问题讨论】:

    标签: scala unit-testing junit mocking mockito


    【解决方案1】:

    这个签名:

    def apply(f: => String)
    

    被称为“按名称调用”,它传递一个表达式而不是评估表达式。这是 Scala 特有的,Mockito 没有很好的支持。

    有很多解决方法:

    one by Eric 看起来最简单,也是您想要的。

    【讨论】:

    • 我无法更改我正在模拟的库类的方法定义...
    猜你喜欢
    • 2015-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-01
    • 2015-02-16
    • 1970-01-01
    • 2014-02-07
    • 2018-09-11
    相关资源
    最近更新 更多