Есть ли способ ввести закрытие groovy как переменную в аргумент предиката Спока? - PullRequest
1 голос
/ 21 февраля 2020

Я нашел интересную строку в документации по взаимодействиям Спока:

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
   }

1 Ответ

2 голосов
/ 22 февраля 2020

Закрытие принимает аргумент, как указано 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
  }
}

Спецификация Спока:

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
...