Mockito: шпионские вызовы функций внутри функциональных интерфейсов? - PullRequest
0 голосов
/ 17 сентября 2018

Mockito, похоже, не в состоянии шпионить за вызовами функций внутри функциональных интерфейсов.Предположим, у меня есть простое приложение Spring Boot с сервисом:

@Service
public class TestService {

    Function<Integer, Integer> mapping = this::add2;

    Integer add2(Integer integer) {
        return integer + 2;
     }

}

и тест:

@SpyBean
TestService testService;

@Test
public void mockitoTest2(){

    doReturn(6).when(testService).add2(2);

    System.out.println(testService.mapping.apply(2));

}

Тест вернет 4 вместо 6. Ожидается ли это или стоитотчет об ошибке?

1 Ответ

0 голосов
/ 18 сентября 2018

Это ожидается. Mockito создает шпиона путем создания мелкой копии , а ссылка на метод this::add2 копируется при сохранении ссылки на старую this.

TestService myTestService = new TestService();
TestService mySpy = Mockito.spy(myTestService);

В этом примере mySpy является экземпляром сгенерированного подкласса TestService , у которого все переопределяемые методы переопределяются для делегирования в Mockito, а все его состояния экземпляра копируются из myTestService. Это означает, что myTestService.mapping == mySpy.mapping, что также означает, что ссылка на this (что означает myTestService), захваченная в функции, скопирована.

Ссылки на методы, примененные к экземпляру, захватывают этот экземпляр, как на странице Oracle в разделе Ссылки на методы в разделе «Виды ссылок на методы». Объект, который получает вызов add2, является оригиналом, а не шпионом, поэтому вы получаете исходное поведение (4), а не поведение, на которое влияет шпион (6).

Это должно быть несколько интуитивно понятно: вы можете вызывать Function<Integer, Integer>, не передавая экземпляр TestService, поэтому вполне разумно, чтобы функция содержала неявную ссылку на реализацию TestService. Вы наблюдаете это поведение, потому что у экземпляра шпиона его состояние скопировано из реального экземпляра после . Функция инициализирована и this сохранено.


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

BiFunction<TestService, Integer, Integer> mapping2 = TestService::add2;

Здесь функция mapping2 не применяется к конкретному объекту, но вместо этого применяется к любому переданному экземпляру TestService. Следовательно, ваш тест вызовет это:

@Test
public void mockitoTest2(){
    doReturn(6).when(testService).add2(2);
    System.out.println(testService.mapping2.apply(testService, 2));
}

... и поскольку вы передаете шпиона testService, он будет обрабатывать вызов виртуального метода для add2 и вызовет поведение, установленное для шпиона (возвращающее 6). Неявно не сохранено this, поэтому ваша функция работает так, как вы ожидаете.

См. Также: Mockito, управляемый: требуется, но не вызывается?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...