2017-09-15 145 views
3

在Groovy单元测试下面的任务是很常见的:在Groovy /斯波克断言调用方法不与斯波克执行

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() 

但出乎意料的是,这并不工作!这两个属性是空的,diff方法失败并带有NotNull-Exception。如果我调试此代码,则永远不会调用方法expected/result

如果我重写按预期工作这样

def result = result(callTheSystemToProduceTheRealResult()) 
def expected = expected(calculateExpectedResult()) 
assert myResult == expected, diff() 

一切的代码。方法被正确调用并且属性被设置。

我的问题是:为什么我不能在assert语句中调用这些方法?这两个代码片段的Groovy/Spock观点有什么不同?

这是一个gist包含所有代码作为运行示例。

回答

3

这很容易解释。断言消息在断言本身之前被评估。下面的代码块完美的作品,但它显示静态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 
}