2017-09-15 148 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 
}