Подтвердить что ты не робот

Mockito: Пытаться шпионить за методом вызывает оригинальный метод

Я использую Mockito 1.9.0. Я хочу издеваться над поведением для одного метода класса в тесте JUnit, поэтому у меня есть

final MyClass myClassSpy = Mockito.spy(myInstance);
Mockito.when(myClassSpy.method1()).thenReturn(myResults);

Проблема в том, что во второй строке myClassSpy.method1() фактически вызывается, что приводит к исключению. Единственная причина, по которой я использую mocks, заключается в том, что позже, когда вызывается myClassSpy.method1(), реальный метод не будет вызываться, и объект myResults будет возвращен.

MyClass - это интерфейс, а myInstance - реализация этого, если это имеет значение.

Что мне нужно сделать, чтобы исправить это шпионское поведение?

4b9b3361

Ответ 1

Позвольте мне процитировать официальную документацию:

Важная информация о шпионаже реальных объектов!

Иногда невозможно использовать, когда (Object) для шпионов. Пример:

List list = new LinkedList();
List spy = spy(list);

//Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
when(spy.get(0)).thenReturn("foo");

//You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);

В вашем случае это выглядит примерно так:

doReturn(resulstIWant).when(myClassSpy).method1();

Ответ 2

Мое дело отличалось от принятого ответа. Я пытался обмануть метод private-private для экземпляра, который не жил в этом пакете

package common;

public class Animal {
  void packageProtected();
}

package instances;

class Dog extends Animal { }

и тестовые классы

package common;

public abstract class AnimalTest<T extends Animal> {
  @Before
  setup(){
    doNothing().when(getInstance()).packageProtected();
  }

  abstract T getInstance();
}

package instances;

class DogTest extends AnimalTest<Dog> {
  Dog getInstance(){
    return spy(new Dog());
  }

  @Test
  public void myTest(){}
}

Компиляция верна, но когда она пытается настроить тест, вместо этого он вызывает реальный метод.

Объявление метода, защищенного или открытого, устраняет проблему, но не является чистым решением.

Ответ 3

Ответ Томаша Нуркевича, похоже, не расскажет всю историю!

NB Версия Mockito: 1.10.19.

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

Этот метод, getContentStringValue, НЕ final и НЕ static.

Эта строка выполняет вызов исходного метода getContentStringValue:

doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), isA( ScoreDoc.class ));

Эта строка не вызывает исходный метод getContentStringValue:

doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), any( ScoreDoc.class ));

По причинам, которые я не могу ответить, использование isA() приводит к сбою предполагаемого (?) метода "не вызывать метод" doReturn.

Посмотрим на используемые здесь сигнатуры методов: они являются static методами Matchers. Оба говорят, что Джавадок возвратил null, что немного сложно окунуться в себя. Предположительно, объект Class передается при проверке параметра, но результат никогда не вычисляется и не отбрасывается. Учитывая, что null может стоять за любой класс и что вы надеетесь, что издеваемый метод не будет вызван, не могли ли сигнатуры isA( ... ) и any( ... ) просто возвращать null, а не общий параметр * <T>?

В любом случае:

public static <T> T isA(java.lang.Class<T> clazz)

public static <T> T any(java.lang.Class<T> clazz)

Документация API не дает никаких сведений об этом. Также, похоже, необходимость такого поведения "не называть метод" "очень редка". Лично я использую этот метод все время: обычно я нахожу, что насмешка включает в себя несколько строк, которые "устанавливают сцену"... после чего следует вызов метода, который затем "разыгрывает" сцену в макете контекст, который вы поставили... и пока вы настраиваете декорации и реквизиты, последняя вещь, которую вы хотите, - это актеры, чтобы они вышли на сцену слева и начали действовать своими сердцами...

Но это далеко за пределами моей оценки зарплаты... Я приглашаю объяснений от любых проходящих мокито первосвященников...

* является "общим параметром" правого члена?

Ответ 4

В моем случае, используя Mockito 2.0, мне пришлось изменить все параметры any() на nullable(), чтобы заглушить реальный вызов.