2010-04-19 11 views
28

public Object doSomething(Object o); die ich verspotten möchte. Es sollte nur seinen Parameter zurückgeben. Ich habe versucht:Wie kann ich eine Methode in easymock verspotten, die einen ihrer Parameter zurückgibt?

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

aber ohne Erfolg, bekomme ich nur eine AssertionError als java.lang.AssertionError: Nothing captured yet. Irgendwelche Ideen?

Antwort

18

Ich war für das gleiche Verhalten suchen, und schließlich das folgende schrieb:

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

} 

Ich schrieb ein schnelles „wie man“ in der javadoc der Klasse.

Hoffe, das hilft.

+0

danke! Obwohl ich den ursprünglichen Komponententest geändert habe, bin ich mir sicher, dass ich wieder auf dieses Problem stoßen werde! (Vielleicht möchten Sie es zur EM-Direktübertragung beitragen?) – Jan

+3

Das Capture ist ein Ablenkungsmanöver in Ihrem Javadoc-Beispiel - es wird nicht benötigt: EasyMock.expect (factory.encode (anyObject())) .undAntwort (parrot) .anyTimes(); – thetoolman

2

Ähm, wenn ich deine Frage richtig verstanden habe, denke ich, dass du es vielleicht zu kompliziert machst.

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

sollte gut funktionieren. Denken Sie daran, dass Sie sowohl den erwarteten Parameter als auch den Rückgabewert angeben. Also benutze das gleiche Objekt in beiden Werken.

+0

I don kenne "someObject" nicht. Es wird in der Methode instanziiert, die ich testen möchte. Denken Sie an eine Methode "createImage (InputStream image)" (cut), die intern einen "Image filter (Image imge)" (Mock) aufruft. – Jan

+0

Ahhh. OK. Dann können Sie ein paar Dinge tun. Zuerst können Sie testen, ob das Objekt eine bestimmte Klasse ist, indem Sie den Argumentvergleicher isA() verwenden. Zweitens würde ich vorschlagen, Ihre eigene Argument Capture zu schreiben. Ich habe das nicht gemacht, aber ich habe meine eigenen Argumentations-Matcher geschrieben. Das ist sehr nützlich, wenn Sie beispielsweise die Eigenschaften von Beans überprüfen möchten. Leider habe ich diesen Code nicht mehr, aber wenn man sich das Beispiel eines Matcher anschaut, ist es nicht schwer. – drekka

+0

Ihr Code ist gültig, aber es beantwortet nicht die Frage, einen der Parameter zu verwenden - es verwendet ein bekanntes Objekt. – thetoolman

22

Nun, der einfachste Weg wäre, das Capture nur in der IAnswer-Implementierung zu verwenden ... wenn Sie dies inline tun, müssen Sie es natürlich final deklarieren.

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) 

Dies ist wahrscheinlich die genaue Art und Weise, ohne auf einige Kontextinformationen zu verlassen. Das macht den Trick für mich jedes Mal.

+0

Ich mag den Post von Remi Fouilloux mehr und benutze ihn sehr oft. Es beseitigt die Notwendigkeit für ein catpure Objekt. – Jan

+0

Große Antwort. Unter Verwendung von Java 8 Lambda's kann die gesamte IAnswer anonyme Unterklasse als "myCapture :: getValue" umgeschrieben werden. –

12

Captures dienen zum Testen der Werte, die anschließend an den Mock übergeben werden. Wenn Sie nur einen Schein benötigen, um einen Parameter (oder einen Wert, der aus dem Parameter berechnet wird) zurückzugeben, müssen Sie nur IAnswer implementieren.

Siehe "Remi Fouilloux" s Implementierung, wenn Sie eine wiederverwendbare Art der Übergabe von Parameter X zurück, aber die Verwendung von Capture im Beispiel ignorieren möchten.

Wenn Sie es nur wie "does_the_trick" beispielsweise inline einfügen möchten, ist das Capture hier ein Reding. Hier ist die vereinfachte Version:

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

dasselbe wie meine bevorzugte Antwort, richtig? – Jan

+0

Nicht ganz, mein Punkt ist, dass in "Remi Fouilloux" s Code das Capture das Javadoc-Beispiel nicht benötigt wird. Es ist auch nicht notwendig in "does_the_trick" Beispiel Code, wie oben verbessert. – thetoolman

7

Basierend auf @does_the_trick und mit Lambda-Ausdrücke, können Sie jetzt schreiben folgendes:

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

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

oder ohne Erfassung als @thetoolman vorgeschlagen

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