Как сопоставить содержимое коллекции при взаимодействии со Споком?

Учитывая, что у меня есть следующий метод в классе, над которым я издеваюсь:

class Foo {
   public void doSomething(Collection<String> input) {
     //...
   }
}

Теперь я издеваюсь над этим классом в своем тесте Spock и хочу проверить взаимодействие:

def test() {
    setup:
    def myMock = Mock(Foo)

    when:
    def hashSet = new HashSet<String>(['foo', 'bar'])
    myMock.doSomething(hashSet)

    then:
    1 * myMock.doSomething(['foo', 'bar'])

}

Однако это взаимодействие не срабатывает. Что действительно странно, так это то, что вывод говорит мне:

too few invocations for:

1 * myMock.doSomething(['foo', 'bar'])   (0 invocations)

Unmatched invocations (ordered by similarity):

1 * myMock.doSomething(['foo', 'bar'])

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

Я делаю что-то не так или это ограничение Спока, и мне нужно проверить содержимое коллекции в закрытии, например

1 * mock.doSomething( { it == ['foo', 'bar'] })

person Jan Thomä    schedule 02.04.2015    source источник


Ответы (1)


Это все потому, что экземпляр HashSet передается в качестве аргумента для имитации вызова, а экземпляр List передается в блоке when. [] - это ArrayList в groovy - есть несоответствие типов - но Set и List, напечатанные на консоли, выглядят очень похоже. Следующий тест работает хорошо:

@Grab('org.spockframework:spock-core:0.7-groovy-2.0')
@Grab('cglib:cglib-nodep:3.1')

import spock.lang.*

class Test extends Specification {

    def "test"() {
        setup:
        def lol = Mock(Lol)

        when:
        def hashSet = new HashSet<String>(['foo', 'bar'])
        lol.doSomething(hashSet)

        then:
        1 * lol.doSomething(new HashSet<String>(['foo', 'bar']))
    }
}

class Lol {
   public void doSomething(Collection<String> input) {
       println input
   }
}
person Opal    schedule 02.04.2015
comment
На самом деле я ожидал, что это сработает независимо от того, какой фактический тип коллекции я использую, поскольку сигнатура метода doSomething ясно указывает, что разрешен ЛЮБОЙ тип Collection‹String›, будь то HashSet, LinkedList, ArrayList или что-то еще. Я действительно не думаю, что это правильно, когда ваш API фактически указывает, что вы можете использовать любую коллекцию, но ваш тест не проходит, если ваш соавтор не использует тот же тип коллекции, который вы использовали для настройки своего макета. - person Jan Thomä; 08.04.2015
comment
С точки зрения контракта это работает хорошо, клиент созданного вами API может использовать любой подтип Collection<String>, но когда дело доходит до тестирования, проверяются точные переданные аргументы, поэтому я не согласен с вами. Если вам нужно проверить, передан ли экземпляр Collection<String>, попробуйте it instanceof Collection<String>. Ответьте сами себе, что вам нужно проверить, актуальные данные или фактический тип данных? Оказывается, это что-то другое. - person Opal; 08.04.2015
comment
Ну, в этом конкретном случае мне нужно проверить данные, меня не волнует тип коллекции. Так что я думаю, мне придется придерживаться закрытия. Так что не совсем лучшее решение, чем у меня сейчас, но, по крайней мере, обсуждение помогло мне, поэтому я принимаю этот ответ. - person Jan Thomä; 08.04.2015