Como funciona a "reflexão estática" em Java? (Ex. Em Mockito ou Easymock)
-
06-07-2019 - |
Pergunta
Eu sou um cara .NET - e codio principalmente em C#.
Desde C# 3.0, podemos alavancar expressões de lambda e árvores de expressão para usar Reflexão estática. Por exemplo, é possível implementar GetMethodName
No snippet seguinte para retornar o nome do método aprovado no parâmetro:
string methodName = GetMethodName( o => o.DoSomething());
Console.WriteLine(methodName); // displays "DoSomething"
Agora, quando olho para as amostras da Mockito (ou as easymock) no mundo Java, vejo:
LinkedList mockedList = mock(LinkedList.class);
when(mockedList.get(0)).thenReturn("first");
Como funciona?
Como é que when
Método funciona? Como isso interpreta mockedList.get(0)
Como uma chamada para o método get com 0 passado como parâmetro E não como um valor?
Solução
As bibliotecas zombeteiras normalmente não funcionam com árvores de expressão. Eles criam um tipo que implementa a interface apropriada e responde às chamadas de método, gravando -as ou validando -as e retornando as respostas pré -programadas. Isso geralmente é feito com um proxy (por exemplo RealProxy na rede, Proxy em java) ou com geração dinâmica de código.
No caso de Easymock, ele usa Proxy
(para interfaces, de qualquer maneira), como você pode ver no código -fonte: veja org.easymock.internal.JavaProxyFactory
.
Outras dicas
As bibliotecas de simulação de Java geralmente funcionam assim:
Quando você cria uma simulação, um proxy real é criado (seja a partir de uma interface ou uma subclasse), a instância está no "Modo de gravação". Isso significa que qualquer chamada subsequente é registrada (nome do método, parâmetros, retorno esperado). Observe que o proxy no modo de gravação não faz nada além de registrar as chamadas. Não há reflexão por se envolver. Nenhuma descoberta de metadados, etc. É claro que essas bibliotecas fazem alguns truques (como armazenar invocações em uma variável local de rosca para lidar com métodos que retornam vazios), mas a idéia permanece a mesma.
Então, quando o "modo de repetição" é iniciado, a instância simulada simplesmente verifica as expectativas da lista de invocações (Método+Parâmetros e Valores de Retorno).
I’ve never worked with mockito or easymock but I don’t think the call does what you think it does. It does not interpret mockedList.get(0)
in any special way. The method get
is executed on the mockedList
object normally, and the result of that is handed in to when
.
mockedList.get(0)
is the syntax for a method call, and does exactly that. What that method does is not exactly clear. mockedList
's runtime type will be a subclass of LinkedList
returned by the mock
method, which can be implemented how ever the mocking framework sees fit.