java 在 Spock 框架中断言两个列表相等
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26283832/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Assert two lists are equal in Spock framework
提问by MiamiBeach
I test my application using Spock framework, the tests are written in Groovy.
我使用 Spock 框架测试我的应用程序,测试是用 Groovy 编写的。
As a result of some method evaluation I have a list of objects. I want to test if this list is the same as the list I expect. I have coded the following:
作为某些方法评估的结果,我有一个对象列表。我想测试这个列表是否与我期望的列表相同。我编写了以下代码:
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
This is one of my first experiences with Groovy, so may be I am missing something?
这是我第一次使用 Groovy 的体验之一,所以我可能遗漏了什么吗?
PS
聚苯乙烯
What confuses me is 'equals' operator in Groovy and Spock. Given Java ArrayList or Java array, equals operator is simply identity operator: equals is ==. In Groovy as far as I understand default equals operator is really equals (form here: http://groovy.codehaus.org/Differences+from+Java). But what is 'equals' for Groovy List or Set?
让我困惑的是 Groovy 和 Spock 中的“等于”运算符。给定 Java ArrayList 或 Java 数组,equals 运算符只是身份运算符:equals 是 ==。在 Groovy 中,据我所知,默认等于运算符实际上是等于(此处的形式:http: //groovy.codehaus.org/Differences+from+Java)。但是 Groovy List 或 Set 的“等于”是什么?
UPDATE
更新
To be more precise. I want to find out wether the two lists have the same objects, no extra objects for both list, the order doesn't matter. For example:
更准确地说。我想知道这两个列表是否具有相同的对象,两个列表都没有额外的对象,顺序无关紧要。例如:
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
回答by tim_yates
Just do:
做就是了:
when:
def expectedResults = [ ... ]
def realResults = getRealResultsMethod()
then:
realResults == expectedResults
Or, if you don't care about order (which is breaking the contract of List, but there you go), you could do:
或者,如果您不关心订单(这违反了 List 的合同,但您可以这样做),您可以这样做:
then:
realResults.sort() == expectedResults.sort()
Or convert them to sets or something
或者将它们转换为集合或其他东西
回答by Opal
If You just need to check if both lists have same elements You may try:
如果您只需要检查两个列表是否具有相同的元素,您可以尝试:
when:
def expectedResults = [ ... ]
def realResults = getRealResultsMethod()
then:
realResults.size() == expectedResults.size()
realResults.containsAll(expectedResults)
expectedResults.containsAll(realResults)
But if You need to check if both lists are equalYou just need (as in @tim_yates' response):
但是,如果您需要检查两个列表是否相等,您只需要(如@tim_yates 的回复):
when:
def expectedResults = [ ... ]
def realResults = getRealResultsMethod()
then:
realResults == expectedResults
Remember that two lists are equal only if they have the same elements in the same order.
请记住,仅当两个列表具有相同顺序的相同元素时,它们才相等。
回答by BalRog
The semantic data structure you are seeking is often referred to as a bag. In a bag, as in a set, order of elements does not matter. However, in a bag, as in a list, repeat elements are allowed. Bag equality, then, consists of having the same elements each in the same amounts, although not necessarily in the same order. So it seems that what you are looking for is a way to apply "bag" semantics to your list. The easiest way to do this is to duplicate one of the bags and remove the other bag's elements from the duplicate until:
您正在寻找的语义数据结构通常称为bag。在包中,就像在集合中一样,元素的顺序无关紧要。但是,在包中,就像在列表中一样,允许重复元素。因此,袋子相等性包括具有相同数量的相同元素,尽管不一定按相同的顺序。因此,您正在寻找的是一种将“袋子”语义应用于您的列表的方法。最简单的方法是复制一个包并从副本中删除另一个包的元素,直到:
- all the other bag's elements are exhausted and the duplicate is empty (they're equal!)
- all the other bag's elements are exhausted and the duplicate is NOT empty (they're different!)
- during the iteration, one of the other bag's elements can't be removed from the duplicate (they're different!)
- 所有其他包的元素都用尽了,副本是空的(它们是相等的!)
- 所有其他包的元素都用完了,副本不是空的(它们是不同的!)
- 在迭代过程中,不能从副本中删除另一个包的元素之一(它们是不同的!)
Something like the equals()
implementation shown below:
类似于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]
Alternatively, if you don't care about the original list order at all, you can represent the bag as a map. The bag element values are the map keys are and the number of appearances of each bag element are the map values. At that point, equality is just map equality.
或者,如果您根本不关心原始列表顺序,则可以将包表示为地图。bag 元素值是映射键,每个 bag 元素出现的次数是映射值。在这一点上,相等只是映射相等。
Like this:
像这样:
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
In any case this is serious overkill if you just need to check order-neutral list equivalence once or twice, but if bag semantics are a frequent need, then defining a Bag class in one of these two ways is probably a good idea.
在任何情况下,如果您只需要检查一次或两次顺序中立的列表等价性,这都是严重的矫枉过正,但如果经常需要袋子语义,那么以这两种方式之一定义 Bag 类可能是一个好主意。
As noted elsewhere, in this specific case, a.sort() == b.sort()
is a sufficient stopgap in place of full bag semantics. However, not all objects that might be placed in a list together are mutually sortable, even with the most sophisticated comparator closure. However, they all have hashCode()
and equals()
, which is all that is needed for either bag implementation shown.
正如其他地方所指出的,在这种特定情况下,a.sort() == b.sort()
是一个足够的权宜之计来代替完整的包语义。但是,即使使用最复杂的比较器闭包,也并非所有可能一起放在列表中的对象都可以相互排序。但是,它们都具有hashCode()
和equals()
,这就是所示的任何一个包实现所需要的。
Furthermore, List.sort()
has O(n log n)algorithmic complexity, whereas all the bag operations shown are O(n)complexity. Not worth worrying about for these small lists, but a much bigger deal for large ones.
此外,List.sort()
具有O(n log n)算法复杂度,而显示的所有袋子操作的复杂度为O(n)。这些小名单不值得担心,但对于大名单来说则要大得多。
回答by MiamiBeach
list1.containsAll(list2) && list2.containsAll(list1)