Как использовать шпионить за ленивым оценки?

1

Я хочу использовать mockito spy.

Когда я устанавливаю возвращаемое значение следующим образом:

when(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user)).thenReturn(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user, fakeNowDate));

doReturn(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user, fakeNowDate)).when(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);

Я вижу, что возвращаемое значение оценивается с нетерпением

что означает, что эта строка "настройка" выполнена.

как я могу заставить шпиона оценить возвращаемое значение только по требованию?

что означает, когда выполняется условие "когда".

Обновить

Благодаря @RobbyCornelissen я пробовал этот код:

    when(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user)).thenAnswer(new Answer() {
        public Object answer(InvocationOnMock invocation) {
            Object[] args = invocation.getArguments();
            ImagesSorter mock = (ImagesSorter)invocation.getMock();
            return mock.sortImages((List<Image>)args[0], (UserInfo)args[1], fakeNowDate);
        }
    });

Но это не помогло:

1) выражение "когда" было вызвано немедленно. (нежелательный)

2) в конечном итоге обратный вызов не был вызван.

Теги:
unit-testing
junit
mockito
spy

2 ответа

1
Лучший ответ

Я не знаю типы аргументов и классов, которые вы используете, поэтому я не могу представить полный пример, но вы можете заглушить использование обратных вызовов с помощью интерфейса " Answer<T>:

Mockito.doAnswer(new Answer() {
    Object answer(InvocationOnMock invocation) {
         ImagesSorter mock = (ImagesSorter) invocation.getMock();
         Object[] args = invocation.getArguments();

         return mock.sortImages((List<Image>) args[0], (UserInfo) args[1],
                 fakeNowDate);
    }
}).when(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
  • 0
    Можете ли вы просмотреть мой код обновления?
  • 0
    Это решило вашу проблему?
Показать ещё 10 комментариев
2

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

EDIT: я не знаю код, и я точно не знаю, какой компонент тестируется, но из того, что я собираю там, типа, ответственного за сортировку изображений, позвольте назвать его ImagesSorter.

  1. Итак, первый случай ImagesSorter - это зависимость испытуемого, так что в этом случае просто обманывает макет ImagesSorter.

  2. Если, однако, сам ImagesSorter тестируется, а очертание специального метода этого класса называется частичным макетом, и это просто неправильно. Он раскрывает внутреннюю часть производственного кода в тесте. Итак, есть несколько решений.

    1. Поскольку в фрагменте кода, показанном в ответе, показан fakeDate, одно из решений - не использовать такие вещи, как new Date() и кодировать простой класс TimeSource, единственная обязанность которого заключается в предоставлении даты. И в тестах bwhavior этого TimeSOurce можно было бы переоценить.

      Более простым решением было бы использовать JodaTime, поскольку он обеспечивает эту встроенную функциональность.

    2. Если объем теста выходит за рамки изменения даты, то, возможно, ImagesSorter нужен способ настройки с другими объектами. Вдохновение о том, как это сделать, можно найти с помощью создателя кеша guava. Если конфигурация мертвая, то простой конструктор coud делает это.

      Это может выглядеть так:

      class ImagesSorter { 
          ImagesSorterAlso algo;
          ImagesSorter(ImagesSorterAlgo algo) { this.algo = algo; }
          Iterable sortImages(...) {
             algo.sort(...);
          }
      }
      
      interface ImagesSorterAlgo {
          Iterable sort(...);
      }
      

Теперь о ваших вопросах:

1) выражение "когда" было вызвано немедленно. (нежелательный)

Ожидается, что imagesSorterSpy является шпионом, поэтому по умолчанию он вызывает реальный код. Вместо этого вы должны использовать альтернативный API, тот же, что показал @RobbyCornelissen. т.е.

doAnswer(sortWithFakeDate()).when(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);

// with BDD aliases (BDDMockito) which I personnaly finds better
willAnswer(sortWithFakeDate()).given(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
will(sortWithFakeDate()).given(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);

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

2) в конечном итоге обратный вызов не был вызван.

Эта проблема, скорее всего, объясняется не равными аргументами. Вам может потребоваться проверить метод equals. Или расслабьте заглушку, используя any().

  • 0
    не могли бы вы рассказать о том, какой лучший дизайн вы предложили в отношении моего кода?
  • 0
    +1 за предупреждение о частичных издевательствах.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню