PowerMockito simula un singolo metodo statico e restituisce un oggetto


98

Voglio deridere un metodo statico m1 da una classe che contiene 2 metodi statici, m1 e m2. E voglio che il metodo m1 restituisca un oggetto.

Ho provato quanto segue

1)

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

Questo chiama sia m1 che m2, che ha un diverso tipo di ritorno, quindi dà un errore di mancata corrispondenza del tipo di ritorno.

2) PowerMockito.when(Static.m1(param1, param2)).thenReturn(1000l); Ma questo non viene chiamato quando viene eseguito m1.

3) PowerMockito.mockPartial(Static.class, "m1"); Fornisce l'errore del compilatore che mockPartial non disponibile, che ho ottenuto da http://code.google.com/p/powermock/wiki/MockitoUsage .

Risposte:


135

Quello che vuoi fare è una combinazione di parte di 1 e tutto di 2.

È necessario utilizzare PowerMockito.mockStatic per abilitare il mocking statico per tutti i metodi statici di una classe. Ciò significa rendere possibile lo stub utilizzando la sintassi when-thenReturn.

Ma l'overload di 2 argomenti di mockStatic che stai utilizzando fornisce una strategia predefinita per ciò che Mockito / PowerMock dovrebbe fare quando chiami un metodo che non hai esplicitamente bloccato sull'istanza mock.

Dal javadoc :

Crea una simulazione di classe con una strategia specifica per le sue risposte alle interazioni. È una funzionalità abbastanza avanzata e in genere non è necessaria per scrivere test decenti. Tuttavia può essere utile quando si lavora con sistemi legacy. È la risposta predefinita, quindi verrà utilizzata solo quando non si interrompe la chiamata al metodo.

La strategia di stubbing predefinita predefinita consiste nel restituire solo null, 0 o false per i metodi oggetto, numero e booleano. Utilizzando l'overload di 2 argomenti, stai dicendo "No, no, no, per impostazione predefinita utilizza il metodo di risposta di questa sottoclasse di risposta per ottenere un valore predefinito. Restituisce un Long, quindi se hai metodi statici che restituiscono qualcosa di incompatibile con Lungo, c'è un problema.

Utilizzare invece la versione a 1 argomento di mockStatic per abilitare lo stubbing dei metodi statici, quindi utilizzare when-thenReturn per specificare cosa fare per un particolare metodo. Per esempio:

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());
  }
}

Il metodo statico con valori di stringa viene sottoposto a stub per restituire "Hello!", Mentre il metodo statico con valori int utilizza lo stubbing predefinito, restituendo 0.


1
Non c'è bisogno di ripetere?
Balaji Boggaram Ramanarayan

Hmm ... sembra più o meno così. Forse PowerMockito fa il replay di PowerMock per te? Mi chiedo anche questo.
Djangofan

3
Ma cosa succede se devo essere sicuro che un metodo statico venga chiamato con argomenti precisi?
elTomato

6
L' @PrepareForTestannotazione dovrebbe essere la classe che chiama il metodo statico, non la classe in cui si trova il metodo statico.
Hazel Troost

5
@HazelTroost - No, l'OP ha ragione. È la classe contenente il metodo statico che dovrebbe essere preparata per il test. Quindi @PrepareForTest(ClassWithStatics.class)è giusto.
arry36
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.