条件条件未按预期工作
Conditional condition not working as expected
我注意到 then
块中条件的评估方式有一个奇怪的行为。应该在执行 when
块之后评估条件,但在一种特定情况下,它会在执行之前执行,因此失败。我能够使用以下简单规范重现该行为:
import spock.lang.Specification
class ConditionalCondition extends Specification {
def 'non-working condition check'() {
given:
def result = 0
when:
System.out.println("----- before: ${result}")
result = 1
System.out.println("----- after: ${result}")
then:
if (true) {
assert result == 1
}
else {
[Mock(Closure)].each {
it.call() >> ""
}
}
}
def 'working condition check'() {
given:
def result = 0
when:
System.out.println("----- before: ${result}")
result = 1
System.out.println("----- after: ${result}")
then:
if (true) {
assert result == 1
}
if (false) {
[Mock(Closure)].each {
it.call() >> ""
}
}
}
}
如果你 运行 以上,你会看到看起来像这样的输出:
ConditionalCondition > non-working condition check FAILED
org.spockframework.runtime.SpockComparisonFailure at ConditionalCondition.groovy:15
ConditionalCondition > working condition check STANDARD_OUT
----- before: 0
----- after: 1
如您所见,即使控制台输出也没有显示,因为 then
块中的代码永远不会执行。报告看起来像这样,再次证实了同样的事实:
non-working condition check
Condition not satisfied:
result == 1
| |
0 false
at ConditionalCondition.non-working condition check(ConditionalCondition.groovy:15)
Tests
Test Duration Result
non-working condition check 0.350s failed
working condition check 0.030s passed
两个测试之间的唯一区别是围绕以下代码的条件:
[Mock(Closure)].each {
it.call() >> ""
}
代码本身对测试没有任何用处,但是当代码是 else
块时它不起作用,但如果它在单独的 if
条件下它工作正常。此外,如果我将代码移出块或完全删除代码,测试将按预期工作。
谁能帮我理解这种奇怪的行为?
为此,您必须深入了解 Spock 的工作原理。
让事情变得像
def "mock example"() {
given:
Receiver receiver = Mock()
def producer = new Producer(receiver)
when:
producer.createItem()
then:
1 * receiver.receive(_) >> true
}
有效,它将 then
块中的所有模拟交互声明直接移到 when
块代码的前面。
这是代码在 AST 转换后的样子。
@org.spockframework.runtime.model.FeatureMetadata(name = 'mock example', ordinal = 2, line = 43, blocks = [org.spockframework.runtime.model.BlockKind.SETUP[]org.codehaus.groovy.ast.AnnotationNode@d9f41, org.spockframework.runtime.model.BlockKind.WHEN[]org.codehaus.groovy.ast.AnnotationNode@d9f41, org.spockframework.runtime.model.BlockKind.THEN[]org.codehaus.groovy.ast.AnnotationNode@d9f41], parameterNames = [])
public void $spock_feature_0_2() {
Receiver receiver = this.MockImpl('receiver', Receiver)
java.lang.Object producer = new Producer(receiver)
this.getSpecificationContext().getMockController().enterScope()
this.getSpecificationContext().getMockController().addInteraction(new org.spockframework.mock.runtime.InteractionBuilder(52, 9, '1 * receiver.receive(_) >> true').setFixedCount(1).addEqualTarget(receiver).addEqualMethodName('receive').setArgListKind(true, false).addEqualArg(_).addConstantResponse(true).build())
producer.createItem()
this.getSpecificationContext().getMockController().leaveScope()
this.getSpecificationContext().getMockController().leaveScope()
}
如果我们获取您的代码,那么我们可以看到发生了同样的事情。
@org.spockframework.runtime.model.FeatureMetadata(name = 'non-working condition check', ordinal = 0, line = 5, blocks = [org.spockframework.runtime.model.BlockKind.SETUP[]org.codehaus.groovy.ast.AnnotationNode@d9f41, org.spockframework.runtime.model.BlockKind.WHEN[]org.codehaus.groovy.ast.AnnotationNode@d9f41, org.spockframework.runtime.model.BlockKind.THEN[]org.codehaus.groovy.ast.AnnotationNode@d9f41], parameterNames = [])
public void $spock_feature_0_0() {
org.spockframework.runtime.ErrorCollector $spock_errorCollector = org.spockframework.runtime.ErrorRethrower.INSTANCE
org.spockframework.runtime.ValueRecorder $spock_valueRecorder = new org.spockframework.runtime.ValueRecorder()
java.lang.Object result = 0
this.getSpecificationContext().getMockController().enterScope()
then:
if (true) {
try {
org.spockframework.runtime.SpockRuntime.verifyCondition($spock_errorCollector, $spock_valueRecorder.reset(), 'result == 1', 16, 24, null, $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(2), $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(0), result) == $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(1), 1)))
}
catch (java.lang.Throwable $spock_condition_throwable) {
org.spockframework.runtime.SpockRuntime.conditionFailedWithException($spock_errorCollector, $spock_valueRecorder, 'result == 1', 16, 24, null, $spock_condition_throwable)}
finally {
}
} else {
[this.MockImpl(null, null, groovy.lang.Closure)].each({
return this.getSpecificationContext().getMockController().addInteraction(new org.spockframework.mock.runtime.InteractionBuilder(20, 21, 'it.call() >> ""').addEqualTarget(it).addEqualMethodName('call').setArgListKind(true, false).addConstantResponse('').build())
})
}
java.lang.System.out.println("----- before: $result")
result = 1
java.lang.System.out.println("----- after: $result")
this.getSpecificationContext().getMockController().leaveScope()
this.getSpecificationContext().getMockController().leaveScope()
}
@org.spockframework.runtime.model.FeatureMetadata(name = 'working condition check', ordinal = 1, line = 25, blocks = [org.spockframework.runtime.model.BlockKind.SETUP[]org.codehaus.groovy.ast.AnnotationNode@d9f41, org.spockframework.runtime.model.BlockKind.WHEN[]org.codehaus.groovy.ast.AnnotationNode@d9f41, org.spockframework.runtime.model.BlockKind.THEN[]org.codehaus.groovy.ast.AnnotationNode@d9f41], parameterNames = [])
public void $spock_feature_0_1() {
org.spockframework.runtime.ErrorCollector $spock_errorCollector = org.spockframework.runtime.ErrorRethrower.INSTANCE
org.spockframework.runtime.ValueRecorder $spock_valueRecorder = new org.spockframework.runtime.ValueRecorder()
java.lang.Object result = 0
java.lang.System.out.println("----- before: $result")
result = 1
java.lang.System.out.println("----- after: $result")
then:
if (true) {
try {
org.spockframework.runtime.SpockRuntime.verifyCondition($spock_errorCollector, $spock_valueRecorder.reset(), 'result == 1', 36, 24, null, $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(2), $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(0), result) == $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(1), 1)))
}
catch (java.lang.Throwable $spock_condition_throwable) {
org.spockframework.runtime.SpockRuntime.conditionFailedWithException($spock_errorCollector, $spock_valueRecorder, 'result == 1', 36, 24, null, $spock_condition_throwable)}
finally {
}
}
this.getSpecificationContext().getMockController().leaveScope()
}
我注意到 then
块中条件的评估方式有一个奇怪的行为。应该在执行 when
块之后评估条件,但在一种特定情况下,它会在执行之前执行,因此失败。我能够使用以下简单规范重现该行为:
import spock.lang.Specification
class ConditionalCondition extends Specification {
def 'non-working condition check'() {
given:
def result = 0
when:
System.out.println("----- before: ${result}")
result = 1
System.out.println("----- after: ${result}")
then:
if (true) {
assert result == 1
}
else {
[Mock(Closure)].each {
it.call() >> ""
}
}
}
def 'working condition check'() {
given:
def result = 0
when:
System.out.println("----- before: ${result}")
result = 1
System.out.println("----- after: ${result}")
then:
if (true) {
assert result == 1
}
if (false) {
[Mock(Closure)].each {
it.call() >> ""
}
}
}
}
如果你 运行 以上,你会看到看起来像这样的输出:
ConditionalCondition > non-working condition check FAILED
org.spockframework.runtime.SpockComparisonFailure at ConditionalCondition.groovy:15
ConditionalCondition > working condition check STANDARD_OUT
----- before: 0
----- after: 1
如您所见,即使控制台输出也没有显示,因为 then
块中的代码永远不会执行。报告看起来像这样,再次证实了同样的事实:
non-working condition check
Condition not satisfied:
result == 1
| |
0 false
at ConditionalCondition.non-working condition check(ConditionalCondition.groovy:15)
Tests
Test Duration Result
non-working condition check 0.350s failed
working condition check 0.030s passed
两个测试之间的唯一区别是围绕以下代码的条件:
[Mock(Closure)].each {
it.call() >> ""
}
代码本身对测试没有任何用处,但是当代码是 else
块时它不起作用,但如果它在单独的 if
条件下它工作正常。此外,如果我将代码移出块或完全删除代码,测试将按预期工作。
谁能帮我理解这种奇怪的行为?
为此,您必须深入了解 Spock 的工作原理。
让事情变得像
def "mock example"() {
given:
Receiver receiver = Mock()
def producer = new Producer(receiver)
when:
producer.createItem()
then:
1 * receiver.receive(_) >> true
}
有效,它将 then
块中的所有模拟交互声明直接移到 when
块代码的前面。
这是代码在 AST 转换后的样子。
@org.spockframework.runtime.model.FeatureMetadata(name = 'mock example', ordinal = 2, line = 43, blocks = [org.spockframework.runtime.model.BlockKind.SETUP[]org.codehaus.groovy.ast.AnnotationNode@d9f41, org.spockframework.runtime.model.BlockKind.WHEN[]org.codehaus.groovy.ast.AnnotationNode@d9f41, org.spockframework.runtime.model.BlockKind.THEN[]org.codehaus.groovy.ast.AnnotationNode@d9f41], parameterNames = [])
public void $spock_feature_0_2() {
Receiver receiver = this.MockImpl('receiver', Receiver)
java.lang.Object producer = new Producer(receiver)
this.getSpecificationContext().getMockController().enterScope()
this.getSpecificationContext().getMockController().addInteraction(new org.spockframework.mock.runtime.InteractionBuilder(52, 9, '1 * receiver.receive(_) >> true').setFixedCount(1).addEqualTarget(receiver).addEqualMethodName('receive').setArgListKind(true, false).addEqualArg(_).addConstantResponse(true).build())
producer.createItem()
this.getSpecificationContext().getMockController().leaveScope()
this.getSpecificationContext().getMockController().leaveScope()
}
如果我们获取您的代码,那么我们可以看到发生了同样的事情。
@org.spockframework.runtime.model.FeatureMetadata(name = 'non-working condition check', ordinal = 0, line = 5, blocks = [org.spockframework.runtime.model.BlockKind.SETUP[]org.codehaus.groovy.ast.AnnotationNode@d9f41, org.spockframework.runtime.model.BlockKind.WHEN[]org.codehaus.groovy.ast.AnnotationNode@d9f41, org.spockframework.runtime.model.BlockKind.THEN[]org.codehaus.groovy.ast.AnnotationNode@d9f41], parameterNames = [])
public void $spock_feature_0_0() {
org.spockframework.runtime.ErrorCollector $spock_errorCollector = org.spockframework.runtime.ErrorRethrower.INSTANCE
org.spockframework.runtime.ValueRecorder $spock_valueRecorder = new org.spockframework.runtime.ValueRecorder()
java.lang.Object result = 0
this.getSpecificationContext().getMockController().enterScope()
then:
if (true) {
try {
org.spockframework.runtime.SpockRuntime.verifyCondition($spock_errorCollector, $spock_valueRecorder.reset(), 'result == 1', 16, 24, null, $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(2), $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(0), result) == $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(1), 1)))
}
catch (java.lang.Throwable $spock_condition_throwable) {
org.spockframework.runtime.SpockRuntime.conditionFailedWithException($spock_errorCollector, $spock_valueRecorder, 'result == 1', 16, 24, null, $spock_condition_throwable)}
finally {
}
} else {
[this.MockImpl(null, null, groovy.lang.Closure)].each({
return this.getSpecificationContext().getMockController().addInteraction(new org.spockframework.mock.runtime.InteractionBuilder(20, 21, 'it.call() >> ""').addEqualTarget(it).addEqualMethodName('call').setArgListKind(true, false).addConstantResponse('').build())
})
}
java.lang.System.out.println("----- before: $result")
result = 1
java.lang.System.out.println("----- after: $result")
this.getSpecificationContext().getMockController().leaveScope()
this.getSpecificationContext().getMockController().leaveScope()
}
@org.spockframework.runtime.model.FeatureMetadata(name = 'working condition check', ordinal = 1, line = 25, blocks = [org.spockframework.runtime.model.BlockKind.SETUP[]org.codehaus.groovy.ast.AnnotationNode@d9f41, org.spockframework.runtime.model.BlockKind.WHEN[]org.codehaus.groovy.ast.AnnotationNode@d9f41, org.spockframework.runtime.model.BlockKind.THEN[]org.codehaus.groovy.ast.AnnotationNode@d9f41], parameterNames = [])
public void $spock_feature_0_1() {
org.spockframework.runtime.ErrorCollector $spock_errorCollector = org.spockframework.runtime.ErrorRethrower.INSTANCE
org.spockframework.runtime.ValueRecorder $spock_valueRecorder = new org.spockframework.runtime.ValueRecorder()
java.lang.Object result = 0
java.lang.System.out.println("----- before: $result")
result = 1
java.lang.System.out.println("----- after: $result")
then:
if (true) {
try {
org.spockframework.runtime.SpockRuntime.verifyCondition($spock_errorCollector, $spock_valueRecorder.reset(), 'result == 1', 36, 24, null, $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(2), $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(0), result) == $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(1), 1)))
}
catch (java.lang.Throwable $spock_condition_throwable) {
org.spockframework.runtime.SpockRuntime.conditionFailedWithException($spock_errorCollector, $spock_valueRecorder, 'result == 1', 36, 24, null, $spock_condition_throwable)}
finally {
}
}
this.getSpecificationContext().getMockController().leaveScope()
}