EasyMock: Void-Methoden

68

Ich habe eine Methode, die void in einer Klasse zurückgibt, die eine Abhängigkeit von der Klasse ist, die ich testen möchte.

Diese Klasse ist riesig und ich verwende nur diese einzige Methode. Ich muss die Implementierung dieser Methode für den Test ersetzen, da ich möchte, dass sie etwas anderes macht, und ich muss in der Lage sein, auf die Parameter zuzugreifen, die diese Methode empfängt.

Ich kann in EasyMock keinen Weg finden, dies zu tun . Ich glaube, ich weiß, wie man es mit Mockito macht , doAnsweraber ich möchte keine weitere Bibliothek hinzufügen, es sei denn, dies ist absolut notwendig.

Iker Jimenez
quelle

Antworten:

93

Wenn ich verstehe, was Sie richtig machen möchten, sollten Sie in der Lage sein 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;
    }
});

Das EasyMock-Benutzerhandbuch erklärt:

Rückgabewerte oder Ausnahmen erstellen

Manchmal möchten wir, dass unser Scheinobjekt einen Wert zurückgibt oder eine Ausnahme auslöst, die zum Zeitpunkt des tatsächlichen Aufrufs erstellt wird. Seit EasyMock 2.2 gibt das von expectLastCall()und zurückgegebene Objekt expect(T value)die Methode zurück andAnswer(IAnswer answer), mit der [Sie] eine Implementierung der Schnittstelle angeben können IAnswer, mit der der Rückgabewert oder die Ausnahme erstellt wird.

Innerhalb eines IAnswerRückrufs sind die an den Scheinaufruf übergebenen Argumente über verfügbar EasyMock.getCurrentArguments(). Wenn Sie diese verwenden, können Refactorings wie das Neuordnen von Parametern Ihre Tests beschädigen. Du wurdest gewarnt.

matt b
quelle
23

Wenn Sie die void-Methode nur für jedes Mal EasyMock.expectLastCall()aufrufen replay(), wenn Sie erwarten, dass sie aufgerufen wird, und sie dann vor dem Aufruf aufrufen , „merkt“ sich Easymock jeden Aufruf.

Ich denke also nicht, dass Sie explizit expect()(außer lastCall) aufrufen müssen, da Sie von einer void-Methode nichts erwarten, außer deren Aufruf.

Danke Chris!

"Fun With EasyMock" von StackOverflow-Kollegen Burt Beckwith ist ein guter Blog-Beitrag, der mehr Details bietet. Bemerkenswerter Auszug:

Grundsätzlich ist der Fluss, den ich normalerweise benutze:

  1. Erstellen Sie einen Mock
  2. Anruf expect(mock.[method call]).andReturn([result])für jeden erwarteten Anruf
  3. Anruf mock.[method call], dann EasyMock.expectLastCall()für jeden erwarteten ungültigen Anruf
  4. Rufen Sie replay(mock)an, um vom Aufnahmemodus in den Wiedergabemodus zu wechseln
  5. Spritzen Sie den Mock nach Bedarf
  6. Rufen Sie die Testmethode auf
  7. Rufen Sie verify(mock)an, um sicherzustellen, dass alle erwarteten Anrufe getätigt wurden
Edward Q. Bridges
quelle
1
Ich denke, diese Antwort geht nicht auf die Frage ein - er möchte nicht nur eine Erwartung an die Methode stellen, sondern auch deren Implementierung ersetzen.
Matt B
1
Guter Punkt Matt, andererseits hat mir dieser Beitrag geholfen zu erkennen, warum die Erwartungsmethode hier nicht wirklich anwendbar ist.
Peter Wippermann
5

Wenn Sie nur später auf die Parameter zugreifen möchten, können Sie auch die Captures- Klasse schätzen, die in EasyMock 2.4 neu ist.

Sie können eine Instanz der Klasse "Capture" anstelle eines Matchers verwenden. Wenn Ihre verspottete Methode aufgerufen wird, speichert die Capture-Instanz den Parameter, mit dem sie aufgerufen wurde.

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());
Piepera
quelle
1

Vielleicht möchten Sie PowerMock ausprobieren. EasyMock basiert auf der Proxy-Reflection-API, dh alles ist ein Proxy, und Sie können nur Schnittstellen und damit nur nicht endgültige Methoden und Klassen testen. Dies mag für einige funktionieren, aber wenn Sie die Welt als gebaut testen, benötigen Sie mehr Leistung.

Mit PowerMock beseitigt die Java 5-Instrumentierungs-API die Einschränkungen. Es ist nicht erforderlich, Scheinobjektimplementierungen des zu testenden Objekts zu schreiben (nur hässliche IMO). Wenn Sie PowerMock mit Mockito (oder JMockit) kombinieren, können Sie wirklich loslegen.

Natürlich gibt es die andere Richtung, Ihren Code neu zu schreiben, um ihn leichter testen zu können. Dies ist im Allgemeinen auch eine gute Idee, wenn möglich.

Joseph Lust
quelle
-1

In solchen Situationen habe ich festgestellt, dass es am besten ist, eine verschachtelte Klasse in meiner Unit-Test-Klasse zu erstellen und die Methoden mit speziellen Anforderungen auf diese Weise zu überschreiben. Wenn Sie also testen, ClassAwelche Methode diese Methode mit den Parametern enthält, auf die Sie zugreifen müssen, gehen Sie wie folgt vor:

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

In meinem Unit-Test-Code verwende ich stattdessen einfach diese Instanz. Behandle es einfach so, als wäre es ein anderes Scheinobjekt. Viel einfacher als das Mischen von Bibliotheken, was meiner Meinung nach wahrscheinlich keine gute Idee ist.

Marc W.
quelle
1
Bereits darüber nachgedacht. Da es sich jedoch um eine abstrakte Klasse handelt, müsste ich etwa 20 leere Methodenimplementierungen bereitstellen oder eines ihrer untergeordneten Elemente unterordnen, was für andere Entwickler, die sich den Test ansehen, etwas verwirrend sein könnte.
Iker Jimenez
Oh ok. Ich wusste nicht, dass es abstrakt ist. Wenn Sie eine IDE verwenden (ich gehe davon aus, dass Sie Eclipse oder NetBeans verwenden), kann sie all diese abstrakten Methoden für Sie in Anspruch nehmen und Sie können einfach einen Kommentar über sie setzen, um zu erklären, was Sie tun. Keine sehr programmatische Lösung, aber zumindest andere Entwickler werden davon nicht verwirrt sein.
Marc W