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

Как работает mockito при() вызове?

Учитывая следующее выражение Mockito:

when(mock.method()).thenReturn(someValue);

Как Mockito собирается создавать прокси-сервер для макета, учитывая, что оператор mock.method() передает возвращаемое значение when()? Я предполагаю, что это использует некоторые вещи CGLib, но было бы интересно узнать, как это технически сделано.

4b9b3361

Ответ 1

Короткий ответ заключается в том, что в вашем примере результат mock.method() будет пустым значением, соответствующим типу; mockito использует косвенную передачу через прокси-сервер, метод перехвата и общий экземпляр класса MockingProgress, чтобы определить, является ли вызов метода для макета для обнуления или повторения существующего затушеванного поведения, а не передачи информации о выполнении stubbing через возвращаемое значение издевающегося метода.

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

Во-первых, когда вы издеваетесь над классом с помощью метода mock класса Mockito, это, по сути, происходит:

  • Mockito.mock делегирует org.mockito.internal.MockitoCore.mock, передавая настройки макета по умолчанию в качестве параметра.
  • MockitoCore.mock делегирует org.mockito.internal.util.MockUtil.createMock
  • Класс MockUtil использует класс ClassPathLoader для получения экземпляра MockMaker для использования для создания макета. По умолчанию используется класс CgLibMockMaker.
  • CgLibMockMaker использует класс, заимствованный из JMock, ClassImposterizer, который обрабатывает создание макета. Ключевыми элементами магии "mockito magic" являются MethodInterceptor, используемые для создания макета: mockito MethodInterceptorFilter и цепочка экземпляров MockHandler, включая экземпляр MockHandlerImpl. Метод перехватчика передает вызовы экземпляру MockHandlerImpl, который реализует бизнес-логику, которая должна применяться при вызове метода на макет (т.е. Поиск, чтобы проверить, был ли уже записан ответ, определяя, является ли вызов новым заглушкой и т.д. Состояние по умолчанию: если заглушка еще не зарегистрирована для вызываемого метода, возвращается возвращаемое значение типа.

Теперь посмотрим на код в вашем примере:

when(mock.method()).thenReturn(someValue)

Вот порядок выполнения этого кода:

  • mock.method()
  • when(<result of step 1>)
  • <result of step 2>.thenReturn

Ключом к пониманию того, что происходит, является то, что происходит, когда вызывается метод на mock: перехватчик метода передается информация о вызове метода и делегирует его цепочке экземпляров MockHandler, которые в конечном итоге делегируются MockHandlerImpl#handle. Во время MockHandlerImpl#handle обработчик mock создает экземпляр OngoingStubbingImpl и передает его в общий экземпляр MockingProgress.

Когда метод when вызывается после вызова method(), он делегирует MockitoCore.when, который вызывает метод stub() того же класс. Этот метод распаковывает текущее завершение из общего экземпляра MockingProgress, в который вызывается посмеянный вызов method() и возвращает его. Затем в экземпляре OngoingStubbing вызывается метод thenReturn.

Ответ 2

Короткий ответ, за кулисами, Mockito использует какие-то глобальные переменные/хранилище для сохранения информации о шагах построения заглушки метода (вызов метода(), когда(), thenReturn() в вашем примере), так что в конечном итоге он может создать карту того, что должно быть возвращено, когда вызывается какой параметр.

Я нашел эту статью очень полезной: Объяснение того, как работают основанные на прокси-серверу Mock Frameworks (http://blog.rseiler.at/2014/06/explanation-how-proxy-based-mock.html). Автор реализовал демонстрационную структуру Mocking, которая я нашел очень хороший ресурс для людей, которые хотят понять, как работают эти Mocking-рамки.

По-моему, это типичное использование Anti-Pattern. Обычно мы должны избегать "побочного эффекта", когда мы реализуем метод, то есть метод должен принимать входные данные и выполнять некоторые вычисления и возвращать результат - кроме этого ничего не изменилось. Но Мокито просто нарушает это правило нарочно. Его методы хранят кучу информации, а также возвращают результат: Mockito.anyString(), mockInstance.method(), когда(), thenReturn, все они имеют специальный "побочный эффект". Вот почему структура выглядит как магия с первого взгляда - мы обычно не пишем такой код. Тем не менее, в издевательском каркасном случае этот анти-шаблонный дизайн является отличным дизайном, поскольку он приводит к очень простому API.