如何将 Groovy 闭包变量注入 Spock 模拟谓词参数?
How to inject Groovy closure variable into Spock mock predicate argument?
我在 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
}
闭包接受一个参数,如 it
所示,具有定义的值。该值是相应的方法参数。因此,无论您在交互之外定义什么闭包,您都需要确保交互将该参数移交给闭包,即您需要创建自己的(小而简单的)闭包来评估外部(可能更长、更复杂)闭包使用参数 it
:
1 * d.validate({ myClosureVar(it) }) >> true
抱歉重复,但我总是喜欢完整的 MCVE 答案,这样您就可以轻松复制、粘贴、编译和 运行:
申请类:
package de.scrum_master.Whosebug.q60341734
class Doer {
boolean validate(int x) {
x == 2
}
}
package de.scrum_master.Whosebug.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.Whosebug.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
我在 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
}
闭包接受一个参数,如 it
所示,具有定义的值。该值是相应的方法参数。因此,无论您在交互之外定义什么闭包,您都需要确保交互将该参数移交给闭包,即您需要创建自己的(小而简单的)闭包来评估外部(可能更长、更复杂)闭包使用参数 it
:
1 * d.validate({ myClosureVar(it) }) >> true
抱歉重复,但我总是喜欢完整的 MCVE 答案,这样您就可以轻松复制、粘贴、编译和 运行:
申请类:
package de.scrum_master.Whosebug.q60341734
class Doer {
boolean validate(int x) {
x == 2
}
}
package de.scrum_master.Whosebug.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.Whosebug.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