I test my application using Spock framework, the tests are written in 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?
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?
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
A simple solution to compare two lists of primitive types for equality is using the List. equals() method. It returns true if both lists have the same size, and all corresponding pairs of elements in both lists are equal.
Using JUnit We can use the logic below to compare the equality of two lists using the assertTrue and assertFalse methods. In this first test, the size of both lists is compared before we check if the elements in both lists are the same. As both of these conditions return true, our test will pass.
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:
then:
realResults.sort() == expectedResults.sort()
Or convert them to sets or something
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 equal You just need (as in @tim_yates' response):
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.
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:
Something like the equals()
implementation shown below:
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With