Вопрос по unit-testing, mocking, mockito – Как работает вызов mockito when ()?

93

Учитывая следующее высказывание Мокито:

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

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

Переименован для наглядности. Paul Morie

Ваш Ответ

2   ответа
94

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

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

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

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

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

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

Вот порядок, в котором этот код будет выполняться:

mock.method()when().thenReturn

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

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

У меня нетЯ еще не помазал мое описание здесь, но я необ этом тоже не забыли. FYI. Paul Morie
Я бы сказал, что вкратце проще перехватить вызов метода внутри другого метода с помощью CGLIB или Javassist, чтобы перехватить, скажем, «если" оператор. Infeligo
Гениальный. На первый взгляд, чтобы это работало, я бы предположил, чтоMockito.when() Нужна ленивая оценка его параметра для работы. Вызовmock.method() будет приостановлено и переданоMockito.when()), затемMockito.when() нужно будет проверить приостановленную операционнуюmock Экземпляр и имяmethod вызов метода, а затем установить предстоящее определение ожидаемого ответаmethod(), JVM потребовалось бы несколько возможностей и функций самоанализа кода во время выполненияесть Но это'все решается наличием статикиMockingProgress хозяйственный элемент. David Tonhofer
@marchaos Это не такя знаю Сwhen(mock.method()).thenXyz(...) синтаксис,mock.method() исполняется в "переигрывать» режим не в "раскорчевка» Режим. Обычно это исполнениеmock.method() не имеет никакого эффекта, поэтому позже, когда (,,thenXyz(...)thenReturnthenThrowthenAnswerи т. д.) исполняется "раскорчевка» режим, а затем записывает желаемый результат для этого вызова метода. Rogério
23

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

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

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

Отличная ссылка.За этим стоит гений: очень простой API, который делает все это очень красивым. Другое хорошее решение заключается в том, что метод when () использует обобщенные значения, так что метод thenReturn () является типобезопасным. David Tonhofer

Похожие вопросы