2010-04-19 13 views
28

public Object doSomething(Object o); che voglio prendere in giro. Dovrebbe solo restituire il suo parametro. Ho provato:Come posso simulare un metodo in easymock che deve restituire uno dei suoi parametri?

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

ma senza successo, ottengo solo un AssertionError come java.lang.AssertionError: Nothing captured yet. Qualche idea?

risposta

18

che cercavo lo stesso comportamento, e, infine, ha scritto quanto segue:

 
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]; 
    } 

} 

ho scritto un rapido "come" nel Javadoc della classe.

Spero che questo aiuti.

+0

grazie! Anche se ho cambiato il test dell'unità originale, sono sicuro che mi imbatterò di nuovo in questo problema! (Forse vuoi contribuire con EM direttamente?) – Jan

+3

The Capture è un'aringa rossa nell'esempio javadoc - non è necessario: EasyMock.expect (factory.encode (anyObject())). AndAnswer (pappagallo) .anyTimes(); – thetoolman

2

Um, se capisco correttamente la tua domanda, penso che potresti finire per complicarla.

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

dovrebbe funzionare bene. Ricorda che stai fornendo sia il parametro previsto che il valore di ritorno. Quindi usando lo stesso oggetto in entrambe le opere.

+0

I don so "someObject". Viene istanziato nel metodo che voglio testare. Pensa a un metodo "createImage (InputStream image)" (tagliato) che internamente chiama "Image filter (Image imge)" (mock). – Jan

+0

Ahhh. ok. Quindi puoi fare un paio di cose. Innanzitutto puoi testare che l'oggetto è una particolare classe usando l'argomento matcher isA(). Secondo, suggerirei di scrivere la tua discussione personale. Non l'ho fatto, ma ho scritto le mie argomentazioni sui matchers. Che è davvero utile se, ad esempio, vuoi controllare le proprietà del bean. Sfortunatamente non ho più quel codice, ma se si guarda l'esempio di scrivere un matcher, non è difficile. – drekka

+0

Il tuo codice è valido ma non risponde alla domanda per utilizzare uno dei parametri - sta usando un oggetto conosciuto. – thetoolman

22

Bene, il modo più semplice sarebbe utilizzare semplicemente Capture nell'implementazione di IAnswer ... quando si esegue questa operazione in linea è necessario dichiararlo final ovviamente.

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) 

Questo è probabilmente il modo più esatto, senza fare affidamento su alcune informazioni di contesto. Questo è il trucco per me ogni volta.

+0

Mi piace di più il post di Remi Fouilloux e lo uso molto spesso. Rimuove la necessità di un oggetto catpure. – Jan

+0

Ottima risposta. Utilizzando Java 8 lambda l'intera sottoclasse anonima IAnswer può essere riscritta come "myCapture :: getValue". –

12

Le acquisizioni servono per testare i valori passati in seguito alla simulazione. Se hai solo bisogno di un mock per restituire un parametro (o un valore calcolato dal parametro), devi solo implementare IAnswer.

Vedere l'implementazione di "Remi Fouilloux" se si desidera un modo riusabile per passare indietro il parametro X, ma ignorare il suo uso di Cattura nell'esempio.

Se si desidera semplicemente inserirlo come nell'esempio "fa_la_trick", di nuovo, la cattura è una falsa pista qui. Ecco la versione semplificata:

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

uguale alla mia risposta preferita, giusto? – Jan

+0

Non proprio, il mio punto è che nel codice "Remi Fouilloux", l'esempio Capture the javadoc non è necessario. Inoltre non è necessario nel codice di esempio "does_the_trick", come descritto sopra. – thetoolman

7

Sulla base @does_the_trick e l'utilizzo di lambda, è ora possibile scrivere il seguente:

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

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

o senza cattura come @thetoolman suggerito

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