2014-10-09 6 views
4

Я тестирую свое приложение с использованием структуры Spock, тесты написаны в Groovy.Утверждение, что два списка равны в структуре Spock

В результате некоторой оценки метода у меня есть список объектов. Я хочу проверить, совпадает ли этот список с списком, который я ожидаю. Я закодировал следующее:

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 и Спока. Учитывая массив Java ArrayList или Java, оператор equals равен просто идентификатору: equals is ==. В Groovy, насколько я понимаю, значение по умолчанию равно оператору, действительно равно (форма здесь: http://groovy.codehaus.org/Differences+from+Java). Но что такое «равно» для Groovy List или Set?

ОБНОВЛЕНИЕ

Чтобы быть более точным. Я хочу узнать, что два списка имеют одни и те же объекты, никаких дополнительных объектов для обоих списков, порядок не имеет значения. Например:

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 
+0

Почему вы не используете 'Set'? – Opal

ответ

9

Вобще:

when: 
    def expectedResults = [ ... ] 
    def realResults = getRealResultsMethod() 

then: 
    realResults == expectedResults 

Или, если вы не заботитесь о порядке (что нарушает договор списка, но там вы идете), вы можете сделать:

then: 
    realResults.sort() == expectedResults.sort() 

или преобразовать их в наборы или что-то

+0

Извините за путаницу, tim_yates, мне нужно [1,5,8] быть равно [5,1,8], вот что я закодировал, но может быть, есть более простое решение. – MiamiBeach

+0

@tim_yates, это не сработает, потому что списки могут содержать элементы в другом порядке. – Opal

+0

@Dymytry Обновленный ответ –

4

Если Вам просто нужно проверить, если оба списка имеют одинаковые элементы Вы можете попробовать:

when: 
    def expectedResults = [ ... ] 
    def realResults = getRealResultsMethod() 

then: 
    realResults.size() == expectedResults.size() 
    realResults.containsAll(expectedResults) 
    expectedResults.containsAll(realResults) 

Но если Вам нужно проверить, если оба списка равные Вам просто нужно (как в ответ @tim_yates'):

when: 
    def expectedResults = [ ... ] 
    def realResults = getRealResultsMethod() 

then: 
    realResults == expectedResults 

Помните, что два списка равны, только если они имеют те же элементы в том же заказать.

+1

Одна небольшая заметка об утверждении containsAll() vs. == on collections: Оператор == в IntelliJ/Spock предоставляет специальную функцию, которая содержитAll: нет. Когда == утверждения терпят неудачу, он предоставляет ссылку на выходе, которая представляет очень хороший вид «Различия». Для других коллекций вам нужно будет скопировать/вставить, чтобы увидеть ваши выходы sidebyside с утверждёнными значениями. – solvingJ

+1

вам нужно проверить containsAll в обоих направлениях. realResults = [1,2,3] и expectedResults = [1,2,2], но не то же самое – Zarremgregarrok

+0

Спасибо @ Zarremgregarrok, вы абсолютно правы. – Opal

-4
list1.containsAll(list2) && list2.containsAll(list1) 
+0

Почему его downvoted? – MiamiBeach

+2

Недостаточно: '[1,1] .containsAll ([1])' is true, а также '[1] .containsAll ([1,1])' и по критериям You это не должно проходить. – Opal

0

Смысловая структура данных вы ищете часто называют мешок. В сумке, как и в наборе, порядок элементов не имеет значения. Однако в сумке, как и в списке, допускаются повторяющиеся элементы. Таким образом, равенство сумм состоит из того, что каждый из них имеет одинаковые элементы в одинаковых количествах, хотя и не обязательно в одном порядке. Таким образом, кажется, что то, что вы ищете, - это способ применить семантику «сумка» к вашему списку. Самый простой способ сделать это, чтобы дублировать один из мешков и удалите элементы другого мешка из дубликата до: (! Они равны)

  • всех элементов другого мешка истощены и дубликат пуст
  • все элементы другого мешка исчерпаны, а дубликат НЕ пуст (они разные!)
  • Во время итерации один из элементов другого мешка не может быть удален из дубликата (они разные!)

Что-то вроде 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 

В любом случае это серьезный перебор, если вам просто нужно проверить порядок нейтрального список эквивалентности один или два раза, но если сумка семантика часто необходима, то определение класс Bag в одном из этих двух способов, вероятно, хорошая идея.

Как указано в другом месте, в данном конкретном случае a.sort() == b.sort() является достаточной стоп-секундой вместо полной семантики пакета. Однако не все объекты, которые могут быть помещены в список вместе, взаимно сортируются, даже с самым сложным закрытием компаратора. Тем не менее, все они имеют hashCode() и equals(). Это все, что необходимо для показанной реализации мешков.

Кроме того, List.sort() имеет O (N журнал N) алгоритмической сложности, в то время как все операции мешка показанных О (п) сложности. Не стоит беспокоиться об этих небольших списках, но гораздо больше для крупных.

Смежные вопросы