Как работает & # 8220; статическое отражение & # 8221; работать в Java? (например, в mockito или easymock)
-
06-07-2019 - |
Вопрос
Я парень .NET, и я в основном пишу на C #.
Начиная с C # 3.0, мы можем использовать лямбда-выражения и деревья выражений для использования статическое отражение . Например, можно реализовать GetMethodName
в следующем фрагменте, чтобы вернуть имя метода, переданного в параметре:
string methodName = GetMethodName( o => o.DoSomething());
Console.WriteLine(methodName); // displays "DoSomething"
Теперь, когда я смотрю на образцы Mockito (или EasyMock) в мире Java, я вижу:
LinkedList mockedList = mock(LinkedList.class);
when(mockedList.get(0)).thenReturn("first");
Как это работает?
Как работает метод when
? Как он интерпретирует mockedList.get (0)
как вызов метода get, где 0 передается как параметр , а не как значение?
Решение
Пересматривающие библиотеки обычно не работают с деревьями выражений. Они создают тип, который реализует соответствующий интерфейс и отвечает на вызовы методов, записывая их или проверяя и возвращая предварительно запрограммированные ответы. Обычно это делается с помощью прокси-сервера (например, RealProxy в .NET, прокси-сервер в Java) или с динамической генерацией кода.
В случае EasyMock он использует Proxy
(для интерфейсов, в любом случае), как вы можете видеть в исходном коде: посмотрите на org.easymock.internal.JavaProxyFactory
. р>
Другие советы
Библиотеки макетов Java обычно работают следующим образом:
Когда вы создаете макет, создается фактический прокси (будь то интерфейс или подкласс), экземпляр находится в «режиме записи». Это означает, что любой последующий вызов записывается (имя метода, параметры, ожидаемый результат). Обратите внимание, что прокси в режиме записи на самом деле ничего не делает, кроме записи звонков. Там нет отражения как такового. Нет обнаружения метаданных и т. Д. Конечно, эти библиотеки выполняют некоторые приемы (например, сохраняют вызовы в локальной переменной потока для обработки методов, возвращающих void), но идея остается той же. Р>
Затем, когда «режим воспроизведения» запускается, фиктивный экземпляр просто проверяет ожидания из списка вызовов (метод + параметры и возвращаемые значения).
Я никогда не работал с mockito или easymock, но я не думаю, что вызов делает то, что вы думаете. Он не интерпретирует mockedList.get (0)
каким-либо особым образом. Метод get
выполняется для объекта mockedList
в обычном режиме, и результат этого передается в when
. р>
mockedList.get (0)
- это синтаксис для вызова метода, который делает именно это. Что этот метод делает, не совсем понятно. Тип времени выполнения mockedList
будет подклассом LinkedList
, возвращаемого методом mock
, который может быть реализован так, как сочтет нужным инфраструктура mocking. р>