【问题标题】:How to inject Groovy closure variable into Spock mock predicate argument?如何将 Groovy 闭包变量注入 Spock 模拟谓词参数?
【发布时间】:2020-06-06 01:34:11
【问题描述】:

我在 Spock 交互文档中发现了一条有趣的语句:

http://spockframework.org/spock/docs/1.3/interaction_based_testing.html#_argument_constraints

最后一行约束,带有闭包谓词的例子:

1 * subscriber.receive({ it.size() > 3 && it.contains('a') })

我的问题是:Groovy 中有没有办法将此谓词作为变量传递?

我的测试环境代码:

class Something {
   Doer doer

   Something(Doer doer) {
      this.doer = doer
   }

   boolean doSth(x) {
      if (!doer.validate(x)) throw new RuntimeException()
      true
   }
}

class Doer {
   boolean validate(int x) {
      x == 2
   }
}

和测试代码:

   def "some test"() {
      given:
      def d = Mock(Doer)
      def s = new Something(d)

      when:
      s.doSth(2)

      then:
      1 * d.validate({ it == 2 }) >> true
   }

我想要达到的目标:

def "some test"() {
      given:
      def d = Mock(Doer)
      def s = new Something(d)
      def myClosureVar = { ??? }

      when:
      s.doSth(2)

      then:
      1 * d.validate(myClosureVar) >> true
   }

【问题讨论】:

  • 我不相信有,我似乎记得它需要在测试的实际定义中,这样 spock 才能使用它的 DSL 魔法

标签: groovy closures spock


【解决方案1】:

闭包接受一个参数,如it 所示,具有定义的值。该值是相应的方法参数。因此,无论您在交互之外定义什么闭包,您都需要确保交互将该参数传递给闭包,即您需要创建自己的(小而简单)闭包来评估外部(可能更长,更复杂)闭包带参数it:

1 * d.validate({ myClosureVar(it) }) >> true

抱歉重复,但我总是更喜欢在我的答案中使用完整的MCVE,以便您可以轻松复制、粘贴、编译和运行:

应用程序类:

package de.scrum_master.stackoverflow.q60341734

class Doer {
  boolean validate(int x) {
    x == 2
  }
}
package de.scrum_master.stackoverflow.q60341734

class Something {
  Doer doer

  Something(Doer doer) {
    this.doer = doer
  }

  boolean doSth(x) {
    if (!doer.validate(x)) throw new RuntimeException()
    true
  }
}

Spock 规范:

package de.scrum_master.stackoverflow.q60341734

import org.junit.Rule
import org.junit.rules.TestName
import spock.lang.Specification

class SomethingTest extends Specification {
  @Rule
  TestName testName

  def "some test"() {
    given:
    def d = Mock(Doer)
    def s = new Something(d)

    when:
    s.doSth(2)

    then:
    1 * d.validate({ println "$testName.methodName: closure parameter = $it"; it == 2 }) >> true
  }

  def "another test"() {
    given:
    def d = Mock(Doer)
    def s = new Something(d)
    def myClosureVar = { println "$testName.methodName: closure parameter = $it"; it == 2 }

    when:
    s.doSth(2)

    then:
    1 * d.validate({ myClosureVar(it) }) >> true
  }
}

控制台日志:

some test: closure parameter = 2
another test: closure parameter = 2

【讨论】:

  • 太好了,它有效 - 谢谢!当您给出 { it == 2 } 的闭包返回闭包时,您是否也能够生成示例,因此在 validate() 中调用该函数也会使测试通过?
  • 但这正是我所做的!测试确实通过了,它确实将it == 2 评估为最后一条语句,并自动将其作为结果。还是我误解了你的问题?
  • 我建议在你的闭包中使用assert,这样你会得到更好的错误报告。
  • 我为什么要在闭包中使用assert?实际上没有任何东西在那里得到验证,闭包只是一个方法参数约束。如果不满足约束,则不会匹配交互,因此不会对结果进行存根,但不会抛出 IMO 断言错误。
猜你喜欢
  • 2016-05-10
  • 1970-01-01
  • 1970-01-01
  • 2013-07-08
  • 2018-08-24
  • 1970-01-01
  • 1970-01-01
  • 2021-11-26
  • 1970-01-01
相关资源
最近更新 更多