在 Groovy/Spock 断言调用方法未执行
In Groovy/Spock assert call methods are not executed
在 Groovy Spock 单元测试中,以下任务很常见:
assert myResult == calculateExpectedResult()
(有或没有 assert
关键字。)
groovy 断言打印出大量信息,说明这里发生了什么以及我的断言失败的原因。但是当比较的对象非常复杂和深入时,获取未通过测试的具体 属性 可能会很棘手。
为此,我发现 Javers Framework 可以很好地比较对象并产生精确的差异。我创建了一个特征来做到这一点:
trait DiffTrait {
Javers javers = JaversBuilder.javers().build()
String diff(result, expected) {
Diff diff = javers.compare(result, expected);
def valueChanges = diff.getChangesByType(ValueChange)
String message = ""
valueChanges.each { message += "\n$it.propertyName = $it.left instead of expected: $it.right" }
return message
}
}
现在我可以像这样在我的单元测试中使用它:
def expected = calculateExpectedResult()
assert myResult == expected, diff(myResult, expected)
这样我就得到了一份打印精美的差异列表。
但这有点冗长,因为我必须指定两次值。
所以我改变了这样的特征:
trait DiffTrait {
Javers javers = JaversBuilder.javers().build()
def result
def expected
String diff(result, expected) {
Diff diff = javers.compare(result, expected);
def valueChanges = diff.getChangesByType(ValueChange)
String message = ""
valueChanges.each { message += "\n$it.propertyName = $it.left instead of expected: $it.right" }
return message
}
String diff() {
diff(result, expected)
}
def result(result) {
this.result = result
return result
}
def expected(expected) {
this.expected = expected
return expected
}
}
我的想法是像这样使用它:
def result = callTheSystemToProduceTheRealResult()
def expected = calculateExpectedResult()
assert result(myResult) == expected(expected), diff()
但令人惊讶的是,这不起作用!这两个属性为 null,diff 方法失败并出现 NotNull-Exception。如果我调试此代码,则永远不会调用 expected
/result
方法!
如果我这样重写代码
def result = result(callTheSystemToProduceTheRealResult())
def expected = expected(calculateExpectedResult())
assert myResult == expected, diff()
一切正常。正确调用方法并设置属性。
我的问题是:为什么我不能在assert语句中调用这些方法?从Groovy/Spock的角度看这两个代码碎片有什么区别?
这是一个 gist 包含所有代码的 运行 示例。
解释起来很容易。断言消息在断言本身之前被评估。以下代码完美运行,但它显示静态 diff
消息:
import org.javers.core.Javers
import org.javers.core.JaversBuilder
import org.javers.core.diff.Diff
import org.javers.core.diff.changetype.ValueChange
import spock.lang.Specification
class LolSpec extends Specification implements DiffTrait {
def 'lol'() {
expect:
def whatIGot = new Lol(l: 'a')
def whatIExpected = new Lol(l: 'b')
assert result(whatIGot) == expected(whatIExpected), 'diff'
}
}
trait DiffTrait {
Javers javers = JaversBuilder.javers().build()
def result
def expected
String diff() {
diff(result, expected)
}
String diff(result, expected) {
Diff diff = javers.compare(result, expected);
def valueChanges = diff.getChangesByType(ValueChange)
String message = ""
valueChanges.each { message += "\n$it.propertyName = $it.left instead of expected: $it.right" }
return message
}
def result(result) {
this.result = result
return result
}
def expected(expected) {
this.expected = expected
return expected
}
}
class Lol {
String l
}
您需要传递参数两次或更改实现,例如:
import groovy.transform.EqualsAndHashCode
import org.javers.core.Javers
import org.javers.core.JaversBuilder
import org.javers.core.diff.changetype.ValueChange
import spock.lang.Specification
class LolSpec extends Specification {
def 'lol'() {
expect:
def whatIGot = new Lol(l: 'a')
def whatIExpected = new Lol(l: 'b')
def diff = new Diff(result: whatIGot, expected: whatIExpected)
assert diff.check(), diff.message()
}
}
class Diff {
Javers javers = JaversBuilder.javers().build()
def result
def expected
String message() {
def diff = javers.compare(result, expected);
def valueChanges = diff.getChangesByType(ValueChange)
String message = ""
valueChanges.each { message += "\n$it.propertyName = $it.left instead of expected: $it.right" }
return message
}
boolean check() {
result.equals(expected)
}
}
@EqualsAndHashCode
class Lol {
String l
}
在 Groovy Spock 单元测试中,以下任务很常见:
assert myResult == calculateExpectedResult()
(有或没有 assert
关键字。)
groovy 断言打印出大量信息,说明这里发生了什么以及我的断言失败的原因。但是当比较的对象非常复杂和深入时,获取未通过测试的具体 属性 可能会很棘手。
为此,我发现 Javers Framework 可以很好地比较对象并产生精确的差异。我创建了一个特征来做到这一点:
trait DiffTrait {
Javers javers = JaversBuilder.javers().build()
String diff(result, expected) {
Diff diff = javers.compare(result, expected);
def valueChanges = diff.getChangesByType(ValueChange)
String message = ""
valueChanges.each { message += "\n$it.propertyName = $it.left instead of expected: $it.right" }
return message
}
}
现在我可以像这样在我的单元测试中使用它:
def expected = calculateExpectedResult()
assert myResult == expected, diff(myResult, expected)
这样我就得到了一份打印精美的差异列表。
但这有点冗长,因为我必须指定两次值。
所以我改变了这样的特征:
trait DiffTrait {
Javers javers = JaversBuilder.javers().build()
def result
def expected
String diff(result, expected) {
Diff diff = javers.compare(result, expected);
def valueChanges = diff.getChangesByType(ValueChange)
String message = ""
valueChanges.each { message += "\n$it.propertyName = $it.left instead of expected: $it.right" }
return message
}
String diff() {
diff(result, expected)
}
def result(result) {
this.result = result
return result
}
def expected(expected) {
this.expected = expected
return expected
}
}
我的想法是像这样使用它:
def result = callTheSystemToProduceTheRealResult()
def expected = calculateExpectedResult()
assert result(myResult) == expected(expected), diff()
但令人惊讶的是,这不起作用!这两个属性为 null,diff 方法失败并出现 NotNull-Exception。如果我调试此代码,则永远不会调用 expected
/result
方法!
如果我这样重写代码
def result = result(callTheSystemToProduceTheRealResult())
def expected = expected(calculateExpectedResult())
assert myResult == expected, diff()
一切正常。正确调用方法并设置属性。
我的问题是:为什么我不能在assert语句中调用这些方法?从Groovy/Spock的角度看这两个代码碎片有什么区别?
这是一个 gist 包含所有代码的 运行 示例。
解释起来很容易。断言消息在断言本身之前被评估。以下代码完美运行,但它显示静态 diff
消息:
import org.javers.core.Javers
import org.javers.core.JaversBuilder
import org.javers.core.diff.Diff
import org.javers.core.diff.changetype.ValueChange
import spock.lang.Specification
class LolSpec extends Specification implements DiffTrait {
def 'lol'() {
expect:
def whatIGot = new Lol(l: 'a')
def whatIExpected = new Lol(l: 'b')
assert result(whatIGot) == expected(whatIExpected), 'diff'
}
}
trait DiffTrait {
Javers javers = JaversBuilder.javers().build()
def result
def expected
String diff() {
diff(result, expected)
}
String diff(result, expected) {
Diff diff = javers.compare(result, expected);
def valueChanges = diff.getChangesByType(ValueChange)
String message = ""
valueChanges.each { message += "\n$it.propertyName = $it.left instead of expected: $it.right" }
return message
}
def result(result) {
this.result = result
return result
}
def expected(expected) {
this.expected = expected
return expected
}
}
class Lol {
String l
}
您需要传递参数两次或更改实现,例如:
import groovy.transform.EqualsAndHashCode
import org.javers.core.Javers
import org.javers.core.JaversBuilder
import org.javers.core.diff.changetype.ValueChange
import spock.lang.Specification
class LolSpec extends Specification {
def 'lol'() {
expect:
def whatIGot = new Lol(l: 'a')
def whatIExpected = new Lol(l: 'b')
def diff = new Diff(result: whatIGot, expected: whatIExpected)
assert diff.check(), diff.message()
}
}
class Diff {
Javers javers = JaversBuilder.javers().build()
def result
def expected
String message() {
def diff = javers.compare(result, expected);
def valueChanges = diff.getChangesByType(ValueChange)
String message = ""
valueChanges.each { message += "\n$it.propertyName = $it.left instead of expected: $it.right" }
return message
}
boolean check() {
result.equals(expected)
}
}
@EqualsAndHashCode
class Lol {
String l
}