¿Cómo funciona la "reflexión estática" en Java? (ej. en mockito o easymock)
-
06-07-2019 - |
Pregunta
Soy un tipo .NET, y codifico principalmente en C #.
Desde C # 3.0, podemos aprovechar las expresiones lambda y los árboles de expresiones para usar reflexión estática . Por ejemplo, es posible implementar GetMethodName
en el siguiente fragmento para devolver el nombre del método pasado en el parámetro:
string methodName = GetMethodName( o => o.DoSomething());
Console.WriteLine(methodName); // displays "DoSomething"
Ahora, cuando miro las muestras de Mockito (o las de EasyMock) en el mundo de Java, veo:
LinkedList mockedList = mock(LinkedList.class);
when(mockedList.get(0)).thenReturn("first");
¿Cómo funciona?
¿Cómo funciona el método when
? ¿Cómo interpreta mockedList.get (0)
como una llamada al método get con 0 pasado como parámetro y no como un valor?
Solución
Las bibliotecas burlonas no suelen funcionar con árboles de expresión. Construyen un tipo que implementa la interfaz apropiada y responde a las llamadas a métodos, ya sea grabándolas o validando y devolviendo las respuestas preprogramadas. Esto generalmente se hace con un proxy (por ejemplo, RealProxy en .NET, Proxy en Java) o con generación dinámica de código.
En el caso de EasyMock, usa Proxy
(para las interfaces, de todos modos), como puede ver en el código fuente: mire org.easymock.internal.JavaProxyFactory
.
Otros consejos
Las bibliotecas simuladas de Java generalmente funcionan así:
Cuando crea un simulacro, se crea un proxy real (ya sea desde una interfaz o una subclase), la instancia está en "modo de grabación". Esto significa que se registra cualquier llamada posterior (nombre del método, parámetros, retorno esperado). Tenga en cuenta que el proxy en modo de grabación en realidad no hace más que grabar las llamadas. No hay reflexión per-se involucrada. Sin descubrimiento de metadatos, etc. Por supuesto, estas bibliotecas hacen algunos trucos (como almacenar invocaciones en una variable local de hilo para manejar métodos que devuelven vacío), pero la idea sigue siendo la misma.
Luego, cuando el " modo de reproducción " se inicia, la instancia simulada simplemente verifica las expectativas de la lista de invocaciones (método + parámetros y valores de retorno).
Nunca he trabajado con mockito o easymock, pero no creo que la llamada haga lo que tú crees. No interpreta mockedList.get (0)
de ninguna manera especial. El método get
se ejecuta en el objeto mockedList
normalmente, y el resultado se entrega a cuando
.
mockedList.get (0)
es la sintaxis para una llamada a método, y hace exactamente eso. Lo que hace ese método no está exactamente claro. El tipo de tiempo de ejecución de mockedList
será una subclase de LinkedList
devuelto por el método mock
, que se puede implementar siempre que el marco de imitación lo considere apropiado.