EasyMock: Métodos de Anulación


Tengo un método que devuelve void 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 de ella. 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 recibe este método.

No puedo encontrar una manera de hacer esto en EasyMock. Creo que sé cómo hacerlo con Mockito usando doAnswer pero no quiero añadir otra biblioteca a menos que sea absolutamente necesario.

Author: naXa, 2009-05-13

5 answers

Si entiendo lo que quieres hacer correctamente, deberías 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:

Creando 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() y expect(T value) proporciona el método andAnswer(IAnswer answer) que permite que [usted] a especificar una implementación de la interfaz IAnswer que se utiliza para crear el valor devuelto o excepción.

Dentro de un IAnswer callback, los argumentos pasados a la llamada mock están disponibles vía EasyMock.getCurrentArguments(). Si utiliza estos, refactorizaciones como reordenamiento de parámetros pueden romper sus pruebas. Usted ha sido advertido.

 88
Author: matt b,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-28 14:45:13

Si llama al método void cada vez que espera que se invoque y luego invoca EasyMock.expectLastCall() antes de llamar a replay(), Easymock "recordará" cada invocación.

Así que no creo que necesites llamar explícitamente expect() (aparte de lastCall) ya que no esperas nada de un método void, excepto su invocación.

Gracias Chris!

"Diversión con EasyMock" {[17] } por otro usuario de StackOverflow Burt Beckwith es una buena entrada de blog que proporciona más detalles. Extracto notable:

Básicamente el flujo que tiendo a usar es:

  1. Crear un simulacro
  2. llame expect(mock.[method call]).andReturn([result]) para cada llamada esperada
  3. llama mock.[method call], luego EasyMock.expectLastCall() para cada llamada de vacío esperada
  4. llama a replay(mock) para cambiar del modo "grabar" al modo "reproducir"
  5. inyecte el simulacro según sea necesario
  6. llame al método de ensayo
  7. llame verify(mock) para asegurarse de que todas las llamadas esperadas sucedieron
 21
Author: Edward Q. Bridges,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:09:36

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 el 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());
 5
Author: piepera,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-10 18:52:41

Es posible que desee comprobar hacia fuera PowerMock. EasyMock se basa en la API de reflexión de proxy, lo que significa que todo es un proxy y solo puede 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 tal como está construido, necesitarás más potencia.

Con PowerMock la API de instrumentación Java 5 elimina las limitaciones. No es necesario escribir implementaciones de objetos simulados del objeto a probar (solo feo IMO). Pareja PowerMock con Mockito (o JMockit) y realmente estarás fuera de las carreras.

Por supuesto, existe la otra dirección de reescribir su código para ser probado más fácilmente, lo que generalmente es una buena idea también, si es posible.

 1
Author: Joseph Lust,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-27 13:20:45

En situaciones como estas he encontrado que hacer una clase anidada en mi clase de prueba unitaria y anular los métodos con requisitos especiales de esa manera es la mejor ruta. Así que si estás probando ClassA que tiene ese método con los parámetros 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 pruebas unitarias, solo uso esta instancia en su lugar. Solo trátalo como si fuera cualquier otro objeto simulado. Mucho más fácil que mezclar bibliotecas, lo que estoy de acuerdo probablemente no es una buena idea.

 -1
Author: Marc W,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-13 16:44:02