2010-04-19 14 views
28

public Object doSomething(Object o); del cual me quiero burlar. Simplemente debería devolver su parámetro. Probé:¿Cómo puedo simular un método en easymock que devolverá uno de sus parámetros?

Capture<Object> copyCaptcher = new Capture<Object>(); 
expect(mock.doSomething(capture(copyCaptcher))) 
     .andReturn(copyCatcher.getValue()); 

pero sin éxito, me sale sólo una AssertionError como java.lang.AssertionError: Nothing captured yet. ¿Algunas ideas?

Respuesta

18

que estaba buscando el mismo comportamiento, y, finalmente, escribió lo siguiente:

 
import org.easymock.EasyMock; 
import org.easymock.IAnswer; 

/** 
* Enable a Captured argument to be answered to an Expectation. 
* For example, the Factory interface defines the following 
* <pre> 
* CharSequence encode(final CharSequence data); 
* </pre> 
* For test purpose, we don't need to implement this method, thus it should be mocked. 
* <pre> 
* final Factory factory = mocks.createMock("factory", Factory.class); 
* final ArgumentAnswer<CharSequence> parrot = new ArgumentAnswer<CharSequence>(); 
* EasyMock.expect(factory.encode(EasyMock.capture(new Capture<CharSequence>()))).andAnswer(parrot).anyTimes(); 
* </pre> 
* Created on 22 juin 2010. 
* @author Remi Fouilloux 
* 
*/ 
public class ArgumentAnswer<T> implements IAnswer<T> { 

    private final int argumentOffset; 

    public ArgumentAnswer() { 
     this(0); 
    } 

    public ArgumentAnswer(int offset) { 
     this.argumentOffset = offset; 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    @SuppressWarnings("unchecked") 
    public T answer() throws Throwable { 
     final Object[] args = EasyMock.getCurrentArguments(); 
     if (args.length < (argumentOffset + 1)) { 
      throw new IllegalArgumentException("There is no argument at offset " + argumentOffset); 
     } 
     return (T) args[argumentOffset]; 
    } 

} 

escribí un rápido "cómo" en el javadoc de la clase.

Espero que esto ayude.

+0

gracias! Aunque cambié la prueba original de la unidad, ¡estoy seguro de que volveré a encontrarme con este problema! (¿Quizás quieras contribuir con la dirección de EM?) – Jan

+3

The Capture es una pista falsa en su ejemplo de javadoc: no es necesario: EasyMock.expect (factory.encode (anyObject())) and Answers (loro) .anyTimes(); – thetoolman

2

Um, si entiendo su pregunta correctamente, creo que puede estar complicando demasiado.

Object someObject = .... ;
expect(mock.doSomething(someObject)).andReturn(someObject);

debería funcionar bien. Recuerde que está suministrando el parámetro esperado y el valor de retorno. Entonces, usar el mismo objeto en ambos trabajos.

+0

Pongo 't sabe "algún Objeto". Se crea una instancia en el método que quiero probar. Piense en un método "createImage (InputStream image)" (corte) que internamente llama "Image filter (Image imge)" (simulación). – Jan

+0

Ahhh. De acuerdo. Entonces puedes hacer un par de cosas. En primer lugar, puede probar que el objeto es una clase particular usando el argumento de argumento isA(). En segundo lugar, le sugiero que escriba su propia captura de argumento. No he hecho eso, pero he escrito mi propio argumento matchers. Lo cual es realmente útil si, por ejemplo, desea verificar las propiedades de los beans. Lamentablemente, ya no tengo ese código, pero si miras el ejemplo de escribir un marcador, no es difícil. – drekka

+0

Su código es válido pero no responde la pregunta para usar uno de los parámetros: está utilizando un objeto conocido. – thetoolman

22

Bueno, la forma más fácil sería simplemente utilizar la captura en la implementación de IAnswer ... al hacer esto en línea, tiene que declararlo final, por supuesto.

MyService mock = createMock(MyService.class); 

final Capture<ParamAndReturnType> myCapture = new Capture<ParamAndReturnType>(); 
expect(mock.someMethod(capture(myCapture))).andAnswer(
    new IAnswer<ParamAndReturnType>() { 
     @Override 
     public ParamAndReturnType answer() throws Throwable { 
      return myCapture.getValue(); 
     } 
    } 
); 
replay(mock) 

Esta es probablemente la forma más exacta, sin depender de cierta información de contexto. Esto hace el truco para mí todo el tiempo.

+0

Me gusta más la publicación de Remi Fouilloux y la uso muy a menudo. Elimina la necesidad de un objeto catpure. – Jan

+0

Gran respuesta. Usando Java 8 lambda, toda la subclase anónima IAnswer se puede reescribir como "myCapture :: getValue". –

12

Las capturas son para probar los valores pasados ​​a la simulación después. Si solo necesita un simulacro para devolver un parámetro (o algún valor calculado a partir del parámetro), solo necesita implementar IAnswer.

Consulte la implementación de "Remi Fouilloux" si desea una forma reutilizable de reenviar el parámetro X, pero ignore el uso de Capture en el ejemplo.

Si solo quieres alinearlo como el ejemplo de "does_the_trick", una vez más, Capture es una pista falsa. Esta es la versión simplificada:

MyService mock = createMock(MyService.class); 
expect(mock.someMethod(anyObject(), anyObject()).andAnswer(
    new IAnswer<ReturnType>() { 
     @Override 
     public ReturnType answer() throws Throwable { 
      // you could do work here to return something different if you needed. 
      return (ReturnType) EasyMock.getCurrentArguments()[0]; 
     } 
    } 
); 
replay(mock) 
+0

igual que mi respuesta preferida, ¿verdad? – Jan

+0

No del todo, mi punto es que en el código de "Remi Fouilloux", el ejemplo de Capture the javadoc no es necesario. Tampoco es necesario en el código de ejemplo "does_the_trick", como se ha mejorado anteriormente. – thetoolman

7

Basado en @does_the_trick y el uso de lambdas, ahora se puede escribir lo siguiente:

MyService mock = EasyMock.createMock(MyService.class); 

final Capture<ParamAndReturnType> myCapture = EasyMock.newCapture(); 
expect(mock.someMethod(capture(myCapture))).andAnswer(() -> myCapture.getValue()); 

o sin captura como @thetoolman sugirió

expect(mock.someMethod(capture(myCapture))) 
.andAnswer(() -> (ParamAndReturnType)EasyMock.getCurrentArguments()[0]); 
Cuestiones relacionadas