java - EasyMock: Métodos nulos
unit-testing mocking (5)
Tengo un método que devuelve el vacío en una clase que es una dependencia de la clase que quiero probar.
Esta clase es enorme y solo estoy usando este método único. Necesito reemplazar la implementación de este método para la prueba ya que quiero que haga algo diferente y necesito poder acceder a los parámetros que este método recibe.
No puedo encontrar la manera de hacerlo en EasyMock . Creo que sé cómo hacerlo con Mockito usando doAnswer
pero no quiero agregar otra biblioteca a menos que sea absolutamente necesario.
En situaciones como estas, he descubierto que hacer una clase anidada en mi clase de prueba unitaria y sobreescribir los métodos con requisitos especiales de esa manera es la mejor ruta. Entonces, si estás probando ClassA
que tiene ese método con los parámetros a los que necesitas acceder, harías algo como:
class MockClassA extends ClassA {
@Override
void specialMethod(String param1, String param2) {
// do logging or manipulation of some sort
super.specialMethod(param1,param2); // if you need to
}
}
En mi código de prueba de unidad, entonces simplemente uso esta instancia en su lugar. Solo trátalo como si fuera cualquier otro objeto simulado. Mucho más fácil que mezclar bibliotecas, y estoy de acuerdo que probablemente no sea una buena idea.
Es posible que desee comprobar PowerMock. EasyMock se basa en la API de proxy de reflexión, lo que significa que todo es un proxy y solo se pueden probar interfaces y, por lo tanto, solo métodos y clases no finales. Esto podría funcionar para algunos, pero si estás probando el mundo como construido, necesitarás más potencia.
Con PowerMock, la API de instrumentación de Java 5 elimina las limitaciones. No es necesario escribir implementaciones de objetos simulados del objeto que se va a probar (solo IMO feo). Junte PowerMock con Mockito (o JMockit) y realmente se irá a las carreras.
Por supuesto, existe la otra dirección de reescribir su código para que sea más fácil de probar, lo cual generalmente también es una buena idea, si es posible.
Si entiendo lo que quiere hacer correctamente, debería poder usar andAnswer()
:
mockObject.someMethod(eq(param1), eq(param2));
expectLastCall().andAnswer(new IAnswer() {
public Object answer() {
//supply your mock implementation here...
SomeClass arg1 = (SomeClass) getCurrentArguments()[0];
AnotherClass arg2 = (AnotherClass) getCurrentArguments()[1];
arg1.doSomething(blah);
//return the value to be returned by the method (null for void)
return null;
}
});
La Guía del usuario de EasyMock explica:
Crear valores de retorno o excepciones
A veces nos gustaría que nuestro objeto simulado devuelva un valor o arroje una excepción que se crea en el momento de la llamada real. Desde EasyMock 2.2, el objeto devuelto por
expectLastCall()
yexpect(T value)
proporciona el métodoandAnswer(IAnswer answer)
que le permite [usted] especificar una implementación de la interfazIAnswer
que se utiliza para crear el valor devuelto o la excepción.Dentro de una
IAnswer
llamada deIAnswer
, los argumentos pasados a la llamada simulada están disponibles a través deEasyMock.getCurrentArguments()
. Si los usa, refactorizaciones como la reordenación de parámetros pueden romper sus pruebas. Usted ha sido advertido.
Si solo desea acceder a los parámetros para más adelante, también puede apreciar la clase Captures , que es nueva en EasyMock 2.4.
Puede usar una instancia de la clase "Capture" en lugar de un matcher. Cuando se invoca su método simulado, la instancia de Capture almacenará el parámetro con el que se invocó.
Capture<ChartPanel> captured = new Capture<ChartPanel>();
// setChartPanel is going to be called during execution;
// we want to verify some things about the ChartPanel
// instance it''s invoked with
chartMock.setChartPanel(capture(captured));
replay(chartMock);
ufdm.setChartAnnotater(chartMock);
// afterPropertiesSet triggers the setChartPanel call...
ufdm.afterPropertiesSet();
verify(chartMock);
// verify some things about the ChartPanel parameter our
// mock object was invoked with
assertSame(plot, captured.getValue().getChart().getPlot());
Si solo llama al método nulo cada vez que espera que se invoque y luego invoque EasyMock.expectLastCall()
antes de llamar a la replay()
, Easymock "recordará" cada invocación.
Así que no creo que deba llamar explícitamente a expect()
(que no sea lastCall
) ya que no espera nada de un método nulo, excepto su invocación.
Gracias Chris!
"Fun With EasyMock" por el usuario de Burt Beckwith es una buena publicación de blog que proporciona más detalles. Extracto notable:
Básicamente, el flujo que tiendo a usar es:
- Crea un simulacro
- call
expect(mock.[method call]).andReturn([result])
para cada llamada esperada- llamada
mock.[method call]
, luegoEasyMock.expectLastCall()
para cada llamada vacía esperada- llamada de
replay(mock)
para pasar del modo "grabación" al modo "reproducción"- inyecta el simulacro según sea necesario
- llamar al método de prueba
- call
verify(mock)
para asegurar que todas las llamadas esperadas ocurrieron