8 Stimmen

Gibt es eine Möglichkeit in JMockit, die ursprüngliche Methode von einer gespotteten Methode aufzurufen?

In meiner Mock-Klasse spotte ich der Methode foo(). Für einige Testfälle möchte ich, dass die Mock-Implementierung von foo() einen speziellen Wert zurückgibt. Für andere Testfälle möchte ich die echte Implementierung von foo() verwenden. Ich habe in meiner Mock-Klasse einen Booleschen Wert definiert, so dass ich in der Mock-Methode festlegen kann, ob ich den speziellen Wert zurückgeben oder die "echte" Methode verwenden möchte. Das Problem ist, dass ich nicht herausfinden kann, wie ich die echte Methode von der nachgebildeten Methode aus aufrufen kann.

Ich habe herausgefunden, dass man innerhalb des Mock-Objekts ein spezielles Mitglied mit dem Namen "it" (mit dem Typ des zu spiegelnden Objekts) definieren kann. Dies ermöglicht es Ihnen, die echte Klasse von der Mock-Implementierung zu referenzieren. Mein Plan war also, wenn ich die "echte" Implementierung von foo() aufrufen müsste, würde die Mock-Methode it.foo() aufrufen. Dies funktioniert jedoch nicht, weil der Aufruf von it.foo() nur die Mock-Version erneut aufruft, nicht die echte Version, so dass ich am Ende eine unendliche Rekursion habe.

Gibt es eine Möglichkeit, dies zu bewerkstelligen?

EDIT: es könnte klarer sein, mit einem Code-Beispiel, hier ist, was meine aktuelle Mocked-Methode-Implementierung wie aussieht:

private RealClass it;
...
public SomeClass foo() {
    if(fakeIt) {
        return new SomeClass("fakevalue");
    } else {
        // doesn't work, just keeps calling the mock foo
        // in infinite recursion
        return it.foo();
    }
}

EDIT 2: Außerdem mache ich für die meisten meiner Testfälle PAS die Mock-Implementierung wünschen. Mein erster Versuch bestand also darin, Mockit.redefineMethods() nur in den Testfällen aufzurufen, in denen ich das Mock-Objekt benötigte. Aber das hat nicht funktioniert - es scheint, dass Sie dies nur innerhalb von setup/teardown tun können ... meine Mock-Implementierung wurde nie aufgerufen, wenn ich das versuchte.

HINWEISE ZUR LÖSUNG:

Zuerst dachte ich nicht, dass die gegebene Antwort funktionierte, aber nach dem Spielen mit ihm einige mehr, es scheint das Problem ist, dass ich JMockit "Kern" Methoden mit der "Annotation" angetrieben Methoden gemischt wurde. Offenbar müssen Sie bei Verwendung der Annotation Mockit.setupMocks verwenden, nicht Mockit.redefineMethods(). Dies ist, was schließlich funktionierte:

@Before 
public void setUp() throws Exception
{
    Mockit.setUpMocks(MyMockClass.class);
}

Dann, für den Probeunterricht:

@MockClass(realClass = RealClass.class)
public static class MyMockClass {
    private static boolean fakeIt = false;
    private RealClass it;

    @Mock(reentrant = true)
    public SomeClass foo() {
        if(fakeIt) {
            return new SomeClass("fakevalue");
        } else {
            return it.foo();
        }
    }
}

13voto

Trevor Robinson Punkte 14524

In neueren Versionen von JMockit, Invocation.proceed() kann aus einem Programm heraus aufgerufen werden MockUp Umsetzung. Siehe Zugriff auf den Aufforderungskontext .

public class MyMockClass extends MockUp<RealClass> {

    private static boolean fakeIt = false;

    @Mock
    public SomeClass foo(Invocation inv) {
        if (fakeIt) {
            return new SomeClass("fakevalue");
        } else {
            return inv.proceed();
        }
    }
}

0 Stimmen

Der Link in dieser Antwort ist ein defekter Link. Neuer Link für JMockIt: ( jmockit.github.io/tutorial/Faking.html#proceed )

8voto

Kris Pruden Punkte 3260

Ich denke, Sie können dies mit dem @Mock Bemerkung. Aus den Unterlagen, @Mock(reentrant=true) in Ihrer Scheinklasse sollte das genügen.

Siehe http://jmockit.googlecode.com/svn/trunk/www/javadoc/mockit/Mock.html
Ein Beispiel dafür finden Sie hier http://jmockit.googlecode.com/svn/trunk/www/tutorial/StateBasedTesting.html#reentrant

Ich habe das aber nicht getestet

0 Stimmen

Ich muss etwas übersehen haben. Aus der Doku klingt es vielversprechend, aber es scheint keine Rolle zu spielen, ob ich reentrent=true oder false verwende, ich erhalte das gleiche Verhalten wie zuvor. Auch die Doku sagt "Standardmäßig sind solche Aufrufe nicht erlaubt, weil sie zu unendlicher Rekursion führen ..." so bin ich verwirrt.

0 Stimmen

Nach einer weiteren Überprüfung fand ich heraus, was mir fehlte :)

0 Stimmen

Ich habe den JavaDoc-Link aktualisiert und einen Beispiel-Link hinzugefügt. +1 Für die Antwort.

1voto

ebo Punkte 2677

Anstatt ein Mock-Objekt zu verwenden, können Sie das zu testende Objekt auch unterklassifizieren und die Methoden überschreiben, die spezielle Werte zurückgeben sollen.

Zum Beispiel:

RealClass toTest = new RealClass(){
      public String foo(){
          return "special value";
      }
}

//use toTest in test

Wenn Sie diese Definition in Ihrem Test beibehalten, ist es auch für andere klar, welche Methoden "gespottet" werden.

0 Stimmen

Danke für die Anregung! Leider kann ich diesen Ansatz nicht verwenden, weil die Klasse, die ich mocking ist eigentlich nicht direkt durch den Testfall erstellt. Sie wurde von dem Objekt erstellt, das getestet wird.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X