Java 断言两个列表在Spock框架中相等
我使用Spock框架测试我的应用程序,测试是用Groovy编写的 作为某种方法评估的结果,我有一个对象列表。我想测试这个列表是否与我期望的列表相同。我已编写了以下代码:Java 断言两个列表在Spock框架中相等,java,groovy,spock,Java,Groovy,Spock,我使用Spock框架测试我的应用程序,测试是用Groovy编写的 作为某种方法评估的结果,我有一个对象列表。我想测试这个列表是否与我期望的列表相同。我已编写了以下代码: def expectedResults = [ ... ] //the list I expect to see def isEqual = true; when: def realResults = getRealResultsMethod() //get real results in a list here expect
def expectedResults = [ ... ] //the list I expect to see
def isEqual = true;
when:
def realResults = getRealResultsMethod() //get real results in a list here
expectedResults.each {isEqual &= realResults.contains(it)}
then:
isEqual
0 * errorHandler.handleError(_) //by the way assert that my errorHandler is never called
这是我使用Groovy的第一次体验,所以我可能错过了什么
PS
让我困惑的是Groovy和Spock中的“equals”操作符。给定Java ArrayList或Java array,equals运算符只是标识运算符:equals is==。据我所知,在Groovy中,默认的equals操作符实际上是equals(这里的形式是:)。但Groovy列表或集合的“等于”是什么
更新
更准确地说。
我想知道这两个列表是否有相同的对象,两个列表都没有额外的对象,顺序无关紧要。例如:
list=[1,5,8]
list1=[5,1,8]
list2=[1,5,8,9]
println(list == list1) //should be equal, if we use == not equal
println(list == list2) //should not be equal, if we use == not equal
只要做:
when:
def expectedResults = [ ... ]
def realResults = getRealResultsMethod()
then:
realResults == expectedResults
或者,如果您不关心订单(这违反了列表的合同,但您可以这样做),您可以:
then:
realResults.sort() == expectedResults.sort()
或者将它们转换为集合或其他东西,如果您只需要检查两个列表是否具有相同的元素,您可以尝试:
when:
def expectedResults = [ ... ]
def realResults = getRealResultsMethod()
then:
realResults.size() == expectedResults.size()
realResults.containsAll(expectedResults)
expectedResults.containsAll(realResults)
但如果你需要检查两个列表是否相等,你只需要(如@tim_yates的回答):
请记住,只有当两个列表具有相同的顺序的相同元素时,它们才是相等的。在一个袋子里,就像在一个集合里一样,元素的顺序并不重要。但是,在包中,如列表中,允许重复元素。因此,袋相等性包括具有相同的元素,每个元素具有相同的数量,尽管不一定具有相同的顺序。所以,似乎您正在寻找一种将“bag”语义应用于列表的方法。最简单的方法是复制其中一个袋子,并从副本中移除另一个袋子的元件,直到:
list1.containsAll(list2) && list2.containsAll(list1)
- 其他包的所有元素都已耗尽,副本为空(它们相等!)
- 其他包的所有元素都已耗尽,副本也不是空的(它们不同!)
- 在迭代过程中,另一个包的元素之一无法从副本中删除(它们是不同的!)
equals()
实现:
class Bag {
List list
Bag(List list) { this.list = list }
@Override boolean equals(that) {
def thisList = list?.clone() ?: []
that instanceof Bag &&
(that?.list ?: []).every { thisList.remove((Object)it) } &&
!thisList
}
@Override int hashCode() { this?.list?.sum { it?.hashCode() ?: 0 } ?: 0 }
@Override String toString() { this?.list?.toString() }
}
def a = [1, 5, 1, -1, 8] as Bag
def b = [5, 1, -1, 8, 1] as Bag // same elements different order
def c = [1, 5, -1, 8] as Bag // same elements different size
def d = [5, 5, 1, -1, 8] as Bag // same elements same size different amounts of each
assert a == b
assert a != c
assert a != d
println a // [1, 5, 1, -1, 8]
println b // [5, 1, -1, 8, 1]
或者,如果您根本不关心原始列表顺序,可以将包表示为地图。行李元素值为地图键,每个行李元素的出现次数为地图值。在这一点上,相等就是映射相等 像这样:
class BagAsMap {
Map map = [:]
BagAsMap(List list) {
(list ?: []).each { map[it] = (map[it] ?: 0) + 1 }
}
@Override boolean equals(that) {
that instanceof BagAsMap && this?.map == that?.map
}
@Override int hashCode() { this?.map?.hashCode() ?: 0 }
@Override String toString() {
'[' + map.keySet().sum { k -> (0..<(map[k])).sum { "${k}, " } }[0..-3] + ']'
}
}
def a1 = [1, 5, 1, -1, 8] as BagAsMap
def b1 = [5, 1, -1, 8, 1] as BagAsMap // same elements different order
def c1 = [1, 5, -1, 8] as BagAsMap // same elements different size
def d1 = [5, 5, 1, -1, 8] as BagAsMap // same elements same size different amounts
assert a1 == b1
assert a1 != c1
assert a1 != d1
println a1
println b1
类BagAsMap{
Map=[:]
BagaMap(列表){
(列表?:[])。每个{map[it]=(map[it]?:0)+1}
}
@覆盖布尔等于(该值){
BagAsMap&&this?.map==that?.map的实例
}
@重写int hashCode(){this?.map?.hashCode()?:0}
@重写字符串toString(){
“['+map.keySet().sum{k->(0..很抱歉搞混了,tim_yates,我需要[1,5,8]等于[5,1,8],这就是我编写的代码,但可能有一个更简单的解决方案。@tim_-yates,这不起作用,因为列表可能包含不同顺序的元素。谢谢,@tim_-yates!但对于原语以外的情况,元素相等不能确保排序后的位置相等,对吗?我的意思是[o1,o2,o2']和[o1,o2',o2]其中o2==o2'都已排序,但list1!=list2sort
只适用于Groovy知道如何比较的元素(主要是compariable
对象)。更通用的解决方案是list1 as Set==List2as Set
。为什么不使用Set
?这还不够:[1,1]。包含所有([1])
和[1]都是正确的。containsAll([1,1])
根据您的标准,这不应该通过。关于断言containsAll()与集合上的==相比:IntelliJ/Spock中的==运算符提供了一个特殊功能,它包含所有未包含的功能:当==断言失败时,它在输出中提供了一个链接,该链接提供了一个非常好的“差异”视图。对于其他集合,您必须执行一些复制/粘贴操作,以便与断言的值并排查看输出。您需要同时检查containsAll。realResults=[1,2,3]和expectedResults=[1,2,2]通过,但不完全相同这仍然不太正确[1,1,2,3]和[1,2,2,3]将通过检查
class BagAsMap {
Map map = [:]
BagAsMap(List list) {
(list ?: []).each { map[it] = (map[it] ?: 0) + 1 }
}
@Override boolean equals(that) {
that instanceof BagAsMap && this?.map == that?.map
}
@Override int hashCode() { this?.map?.hashCode() ?: 0 }
@Override String toString() {
'[' + map.keySet().sum { k -> (0..<(map[k])).sum { "${k}, " } }[0..-3] + ']'
}
}
def a1 = [1, 5, 1, -1, 8] as BagAsMap
def b1 = [5, 1, -1, 8, 1] as BagAsMap // same elements different order
def c1 = [1, 5, -1, 8] as BagAsMap // same elements different size
def d1 = [5, 5, 1, -1, 8] as BagAsMap // same elements same size different amounts
assert a1 == b1
assert a1 != c1
assert a1 != d1
println a1
println b1