2009-02-19 11 views
6

Esto podría parecer una pregunta muy detallada sobre Easymock, pero me está costando encontrar un sitio de soporte/foro/lista de correo para esta biblioteca.Easymock: ¿importa el orden de las capturas?

Me encuentro con un error cuando se utiliza el método captures() que parece devolver los parámetros capturados fuera de servicio.

Aquí hay una versión simplificada de lo que estoy probando:

public class CaptureTest extends TestCase { 

    // interface we will be mocking 
    interface Processor { 
      void process(String x); 
    } 

    // class that uses the interface above which will receive the mock 
    class Component { 

     private Processor processor; 

     private String[] s = { "one", "two", "three", "four" }; 

     Component(Processor processor) { 
      this.processor = processor; 
     } 

     public void doSomething() { 
      for (int i = 0; i < s.length; i++) { 
       processor.process(s[i]); 
      } 
     } 
} 

    public void testCapture() { 

     //create the mock, wire it up  
     Processor mockProcessor = createMock(Processor.class); 
     Component component = new Component(mockProcessor); 

     //we're going to call the process method four times 
     //with different arguments, and we want to capture 
     //the value passed to the mock so we can assert against it later  
     Capture<String> cap1 = new Capture<String>(); 
     Capture<String> cap2 = new Capture<String>(); 
     Capture<String> cap3 = new Capture<String>(); 
     Capture<String> cap4 = new Capture<String>(); 

     mockProcessor.process(and(isA(String.class), capture(cap1))); 
     mockProcessor.process(and(isA(String.class), capture(cap2))); 
     mockProcessor.process(and(isA(String.class), capture(cap3))); 
     mockProcessor.process(and(isA(String.class), capture(cap4))); 

     replay(mockProcessor); 

     component.doSomething(); 

     //check what values were passed to the mock 
     assertEquals("one", cap1.getValue()); 
     assertEquals("two", cap2.getValue()); 
     assertEquals("three", cap3.getValue()); 
     assertEquals("four", cap4.getValue()); 

     verify(mockProcessor); 
    } 

} 

(Tenga en cuenta que esto es sólo un caso de prueba simplificada - Yo sé que podría especificar el valor exacto de los argumentos que esperan pasado a mi simulacro, pero en mi caso real los argumentos son objetos complejos con un puñado de campos, y quiero capturar el objeto para que pueda afirmar contra solo algunos de esos campos sin volver a crear todo el objeto en mi caso de prueba).

Cuando ejecuto la prueba, se produce un error en:

junit.framework.ComparisonFailure: se esperaba: < [un]> pero era: < [cuatro]>

Lo que significa que la El parámetro que EasyMock está capturando en cap1 no es la primera llamada al método, pero la última (dado que el valor es four). Obtengo los mismos resultados si invierto las declaraciones captures(), es decir, uso cap4 con la primera llamada al método, etc.

Parece que podría ser un error dentro de EasyMock: diferentes parámetros pasados ​​al mismo método en diferentes invocaciones no parece ser capturado correctamente

¿Alguien más está usando capture() con EasyMock y tiene problemas similares? ¿Hay alguna solución fácil que conozcas o una forma diferente de capturar los parámetros que se pasan a los métodos de mi simulacro?

Actualización 1: ejemplo de código fijo para mostrar que estoy usando createMock, no createStrictMock, pero me da el mismo error con ambos (aunque el valor real de lo que capta los cambios).

+0

He estado viendo este problema y es bastante confuso. Si realiza una instrucción System.out.println en cada una de las capturas, verá lo siguiente con createMock: cuatro, cuatro, cuatro, cuatro. Con un createStrickMock: dos, dos, tres, cuatro. – hooknc

+0

¡Eso definitivamente suena como un error! He enviado un error en la página sourceforge de Easymock, con suerte alguien responderá, aunque por la falta de listas de correo, foros/comentarios en la página principal, etc., tengo la sensación de que el soporte es extremadamente limitado :( –

Respuesta

4

He recibido an answer en el error que envié al sitio de EasyMock sourceforge, y un desarrollador ha confirmado que de hecho es un error con esta versión de Easymock.

De hecho, es un error. La captura se realiza incluso si ya se realizó. El solución actual es implementar su propio objeto de captura y anular setValue para hacer esto:

@Override 
public void setValue(T value) { 
    if(!hasCaptured()) { 
    super.setValue(value); 
    } 
} 
-1

En lugar de llamar EasyMock.createStrictMock (...) sólo llamar EasyMock.createMock (...). Debería resolver tus problemas.

+0

tuve los mismos problemas con createMock - Lo cambié a createStrickMock (y olvidé que estaba en el ejemplo del código que publiqué) pensando que podría ayudar con el orden de las llamadas al método, pero no - el mismo resultado. Actualizaré el ejemplo anterior. –

+0

Hmm, solo como un cheque, ¿podría intentar llamar a checkOrder (falso) después de crear el simulacro? Me puede estar perdiendo algo obvio, pero se ve como un error. Voy a poder confirmarlo en mi máquina esta noche. –

+0

mismos resultados con checkOrder (falso) –

0

También puede intentar usar EasyMock.createNiceMock (...) en lugar de EasyMock.createStrictMock (...) o EasyMock.createMock (...).

Aunque, estoy de acuerdo en que se parece más a un error con createMock.

1

Estaba jugando con su prueba y no pude resolverlo. Sin embargo, amplié la clase de captura para ver si los valores se establecieron en un orden diferente (sospechaba que EasyMock internamente estaba usando un hash con una clave generada a partir de los métodos y los parámetros). Me equivoqué, los métodos están establecidos en el correcto orden. Pero hay algo realmente extraño sucediendo ... Parece que el algoritmo hace algún tipo de patrón de asignación ... Bueno, déjame mostrar el código y la salida extraña ... Por cierto, los cambios de simulacro, niceMock y strictMock no hicieron ninguna diferencia ..

class MyCapture extends Capture<String> { 

    private String id; 

    public MyCapture(String id) { 
     super(); 
     System.out.printf("Constructor %s expecting %s\n", id, this.getClass().getName()); 
     this.id = id; 
    } 

    private static final long serialVersionUID = 1540983654657997692L; 

    @Override 
    public void setValue(String value) { 
     System.out.printf("setting value %s expecting %s \n", value, id); 
     super.setValue(value); 
    } 

    @Override 
    public String getValue() { 
     System.out 
       .printf("getting value %s expecting %s \n", super.getValue(), id); 
     return super.getValue(); 
    } 
} 


public void testCapture() { 

    // create the mock, wire it up 
    Processor mockProcessor = createStrictMock(Processor.class); 
    Component component = new Component(mockProcessor); 

    // we're going to call the process method four times 
    // with different arguments, and we want to capture 
    // the value passed to the mock so we can assert against it later 
    Capture<String> cap1 = new MyCapture("A"); 
    Capture<String> cap2 = new MyCapture("B"); 
    Capture<String> cap3 = new MyCapture("C"); 
    Capture<String> cap4 = new MyCapture("D"); 

    mockProcessor.process(and(isA(String.class), capture(cap1))); 
    mockProcessor.process(and(isA(String.class), capture(cap2))); 
    mockProcessor.process(and(isA(String.class), capture(cap3))); 
    mockProcessor.process(and(isA(String.class), capture(cap4))); 
    replay(mockProcessor); 

    component.doSomething(); 

    // check what values were passed to the mock 
    assertEquals("A", cap1.getValue()); 
    assertEquals("B", cap2.getValue()); 
    assertEquals("C", cap3.getValue()); 
    assertEquals("D", cap4.getValue()); 

    verify(mockProcessor); 
} 

}

* Y esta es la salida *

Constructor A expecting com.comp.core.dao.impl.CaptureTest$MyCapture 
    Constructor B expecting com.comp.core.dao.impl.CaptureTest$MyCapture 
    Constructor C expecting com.comp.core.dao.impl.CaptureTest$MyCapture 
    Constructor D expecting com.comp.core.dao.impl.CaptureTest$MyCapture 
    calling process A 
    setting value A expecting A 
    calling process B 
    setting value B expecting A <<Setting the wrong guy 
    setting value B expecting A <<Setting the wrong guy 
    setting value B expecting B <<Ops this is the right one..stop 
    calling process C 
    setting value C expecting B <<Setting the wrong guy 
    setting value C expecting B <<Setting the wrong guy 
    setting value C expecting C <<Setting the wrong guy 
    calling process D 
    setting value D expecting C <<Setting the wrong guy 
    setting value D expecting C <<Setting the wrong guy 
    setting value D expecting D <<Ops this is the right one..stop 
    getting value B expecting A 

Lo siento, no puedo ayudarte más. Podría ser un error en el simulacro fácil.

0

Este es un problema más apropiado para la prueba basada en el estado, creo. Con JMockit, se podría resolver de esta manera:

import mockit.*; 
import static mockit.Mockit.*; 
import mockit.integration.junit3.*; 

public class CaptureTest extends JMockitTestCase 
{ 
    interface Processor { void process(String x); } 

    class Component 
    { 
     private final Processor processor; 
     private final String[] s = {"one", "two", "three", "four"}; 

     Component(Processor processor) { this.processor = processor; } 

     public void doSomething() 
     { 
     for (String value : s) { 
      processor.process(value); 
     } 
     } 
    } 

    @MockClass(realClass = Processor.class) 
    static class MockProcessor 
    { 
     private final String[] expectedValues; 
     private int i; 

     MockProcessor(String... expectedValues) { this.expectedValues = expectedValues; } 

     @Mock 
     void process(String x) 
     { 
     assertEquals(expectedValues[i++], x); 
     } 
    } 

    public void testCapture() 
    { 
     Processor mockProcessor = setUpMock(new MockProcessor("one", "two", "three", "four")); 
     Component component = new Component(mockProcessor); 

     component.doSomething(); 
    } 
} 
0

En resumen, esto es lo que funcionó para mí:

MyClass myMock = EasyMock.createStrictMock(MyClass.class); 

...

EasyMock.checkOrder(myMock, true); // before the capture and verify, not sure if it matters 

...

Capture<MyArg> capturedArgs = new Capture<MyArg>(); 
expect(myMock.search(capture(capturedArgs))).andReturn(someRandomReturn); 

PD: Estoy usando E asyMock 3.0

Cuestiones relacionadas