PowerMockito verspottet eine einzelne statische Methode und gibt ein Objekt zurück

98

Ich möchte eine statische Methode m1 aus einer Klasse verspotten, die zwei statische Methoden enthält, m1 und m2. Und ich möchte, dass die Methode m1 ein Objekt zurückgibt.

Ich habe folgendes versucht

1)

PowerMockito.mockStatic(Static.class, new Answer<Long>() {
         @Override
         public Long answer(InvocationOnMock invocation) throws Throwable {
            return 1000l;
         }
      });

Dies ruft sowohl m1 als auch m2 auf, die einen anderen Rückgabetyp haben, sodass ein Fehler bei der Nichtübereinstimmung des Rückgabetyps auftritt.

2) PowerMockito.when(Static.m1(param1, param2)).thenReturn(1000l); Dies wird jedoch nicht aufgerufen, wenn m1 ausgeführt wird.

3) PowerMockito.mockPartial(Static.class, "m1"); Gibt dem Compiler einen Fehler, dass mockPartial nicht verfügbar ist, den ich von http://code.google.com/p/powermock/wiki/MockitoUsage erhalten habe .

user1393653
quelle

Antworten:

135

Was Sie tun möchten, ist eine Kombination aus Teil 1 und 2.

Sie müssen PowerMockito.mockStatic verwenden, um das statische Verspotten für alle statischen Methoden einer Klasse zu aktivieren . Dies bedeutet, dass es möglich ist , sie mit der when-thenReturn-Syntax zu stubben.

Die von Ihnen verwendete Überladung von mockStatic mit zwei Argumenten liefert jedoch eine Standardstrategie für die Vorgehensweise von Mockito / PowerMock, wenn Sie eine Methode aufrufen, die Sie in der Mock-Instanz nicht explizit gestoppt haben.

Aus dem Javadoc :

Erstellt ein Klassenmodell mit einer bestimmten Strategie für die Antworten auf Interaktionen. Es ist eine ziemlich fortgeschrittene Funktion, die Sie normalerweise nicht benötigen, um anständige Tests zu schreiben. Dies kann jedoch hilfreich sein, wenn Sie mit Legacy-Systemen arbeiten. Dies ist die Standardantwort und wird nur verwendet, wenn Sie den Methodenaufruf nicht stoppen.

Die Standard- Stubbing-Standardstrategie besteht darin, für Methoden mit Objekt-, Zahlen- und Booleschen Werten nur null, 0 oder false zurückzugeben. Wenn Sie die 2-Argument-Überladung verwenden, sagen Sie: "Nein, nein, nein, verwenden Sie standardmäßig die Antwortmethode dieser Antwort-Unterklasse, um einen Standardwert zu erhalten. Sie gibt ein Long zurück. Wenn Sie also statische Methoden haben, die etwas zurückgeben, das mit nicht kompatibel ist." Lange gibt es ein Problem.

Verwenden Sie stattdessen die 1-arg-Version von mockStatic, um das Stubben statischer Methoden zu aktivieren, und verwenden Sie dann when-thenReturn, um anzugeben, was für eine bestimmte Methode zu tun ist. Beispielsweise:

import static org.mockito.Mockito.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

class ClassWithStatics {
  public static String getString() {
    return "String";
  }

  public static int getInt() {
    return 1;
  }
}

@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassWithStatics.class)
public class StubJustOneStatic {
  @Test
  public void test() {
    PowerMockito.mockStatic(ClassWithStatics.class);

    when(ClassWithStatics.getString()).thenReturn("Hello!");

    System.out.println("String: " + ClassWithStatics.getString());
    System.out.println("Int: " + ClassWithStatics.getInt());
  }
}

Die statische Methode mit String-Wert wird gestubbt, um "Hallo!" Zurückzugeben, während die statische Methode mit int-Wert das Standard-Stubbing verwendet und 0 zurückgibt.

Tom Tresansky
quelle
1
Ist keine Wiederholung erforderlich?
Balaji Boggaram Ramanarayan
Hmm ... irgendwie scheint es so. Vielleicht spielt PowerMockito das PowerMock für Sie ab? Darüber wundere ich mich auch.
Djangofan
3
Aber was ist, wenn ich sicher sein muss, dass eine statische Methode mit präzisen Argumenten aufgerufen wird?
ElTomato
6
Die @PrepareForTestAnnotation sollte die Klasse sein, die die statische Methode aufruft , nicht die Klasse, in der sich die statische Methode befindet.
Hazel Troost
5
@HazelTroost - Nein, das OP ist richtig. Es ist die Klasse, die die statische Methode enthält, die für den Test vorbereitet werden soll. Also @PrepareForTest(ClassWithStatics.class)ist richtig.
Arry36