groovy 在Spock的where块中使用赋值的参数Assert模拟调用

sf6xfgos  于 2022-11-01  发布在  其他
关注(0)|答案(1)|浏览(229)

我有一个方法,其中生成一个标识符,将其发送到某个外部依赖项并返回。我希望有一个单元测试,测试是否返回了发送到那里的相同值
假设测试和代码如下所示:

def "test"() {
    given:
      def testMock = Mock(TestMock)
    and:
      def x
    when:
      def testClass = new TestClass()
      x = testClass.callMethod(testMock)
    then:
      1 * testMock.method(x)
  }

  static interface TestMock {
    void method(double x)
  }

  static class TestClass {
    double callMethod(TestMock mock) {
      double x = Math.random()
      mock.method(x)
      return x
    }
  }

代码工作正常,但测试失败,并显示一条消息:

One or more arguments(s) didn't match:
0: argument == expected
   |        |  |
   |        |  null
   |        false
   0.5757686318956925

因此,看起来then中的模拟检查是在when块中赋值之前完成的。
有没有办法让Spock在检查模拟调用之前分配这个值?或者我可以用不同的方法来做这个检查吗?
我唯一的想法是向方法(或者实际上是类)注入一个id生成器,并在测试中将其存根,但这会使代码复杂化,我希望避免这样做。

我根据kriegaex注解修复了代码示例。

oknrviil

oknrviil1#

修复示例代码

在我们开始之前,您的示例代码有两个问题:

  • 1 * testMock(x)应该是1 * testMock.method(x)
  • callMethod应返回double,而不是int,因为否则结果将始终为0(0和1之间的双精度浮点数在转换为整数时将始终生成0)。

下次请确保您的示例代码不仅能编译,而且能完成预期的任务。示例代码只有在没有额外bug的情况下才有帮助,帮助您的人需要先修复这些bug,然后才能专注于实际问题。

眼前的问题

正如您已经注意到的,交互即使是在then:块中按词法定义的,也会通过Spock的编译器AST转换进行转换,当mock被初始化时,它们被注册在mock上。这是必要的,因为在调用when:块中的任何方法之前,mock必须准备好。在已经执行了when:块的情况下,试图直接使用一个以后才知道的结果,将导致您描述的问题。* 先有鸡还是先有蛋?* 在这种情况下,您不能指定方法参数约束,使用另一个方法调用约束中的mock方法的未来结果。

解决方法

一种可能的解决方法是将方法存根化,并捕获闭包中的参数来计算存根结果,例如>> { args -> arg = args[0]; return "stubbed" }。当然,在Groovy中闭包或方法的最后一条语句中,return关键字是多余的。在您的示例中,方法甚至是void,因此在这种情况下您根本不需要返回任何内容。

示例

我修改了您的示例代码,重命名了类、方法和变量,以便更清楚地描述哪些是什么以及正在发生什么:
第一个
请在Groovy Web Console中尝试。

相关问题