PowerMockito simula un método estático único y un objeto de retorno

98

Quiero simular un método estático m1 de una clase que contiene 2 métodos estáticos, m1 y m2. Y quiero que el método m1 devuelva un objeto.

Intenté lo siguiente

1)

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

Esto está llamando tanto a m1 como a m2, que tiene un tipo de retorno diferente, por lo que da un error de no coincidencia de tipo de retorno.

2) PowerMockito.when(Static.m1(param1, param2)).thenReturn(1000l); Pero esto no se llama cuando se ejecuta m1.

3) PowerMockito.mockPartial(Static.class, "m1"); Da un error del compilador que mockPartial no está disponible, que obtuve de http://code.google.com/p/powermock/wiki/MockitoUsage .

usuario1393653
fuente

Respuestas:

135

Lo que quiere hacer es una combinación de parte de 1 y todo de 2.

Necesita usar PowerMockito.mockStatic para habilitar la simulación estática para todos los métodos estáticos de una clase. Esto significa que es posible apuntarlos usando la sintaxis when-thenReturn.

Pero la sobrecarga de 2 argumentos de mockStatic que está utilizando proporciona una estrategia predeterminada para lo que Mockito / PowerMock debería hacer cuando llama a un método que no ha anotado explícitamente en la instancia simulada.

Desde el javadoc :

Crea un simulacro de clase con una estrategia específica para sus respuestas a las interacciones. Es una función bastante avanzada y, por lo general, no la necesita para escribir pruebas decentes. Sin embargo, puede resultar útil cuando se trabaja con sistemas heredados. Es la respuesta predeterminada, por lo que se usará solo cuando no se apruebe la llamada al método.

El defecto estrategia stubbing defecto es simplemente nula retorno, 0 o falsa para el objeto, número y boolean métodos valorados. Al usar la sobrecarga de 2 argumentos, está diciendo "No, no, no, de forma predeterminada, use el método de respuesta de esta subclase de Respuesta para obtener un valor predeterminado. Devuelve un Long, por lo que si tiene métodos estáticos que devuelven algo incompatible con Largo, hay un problema.

En su lugar, use la versión de 1 argumento de mockStatic para habilitar el apéndice de métodos estáticos, luego use when-thenReturn para especificar qué hacer para un método en particular. Por ejemplo:

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

El método estático con valor de cadena se codifica para devolver "¡Hola!", Mientras que el método estático con valor int utiliza el código auxiliar predeterminado, devolviendo 0.

Tom Tresansky
fuente
1
¿No es necesario volver a jugar?
Balaji Boggaram Ramanarayan
Hmm ... algo así parece. ¿Quizás PowerMockito hace la reproducción de PowerMock por ti? También me pregunto sobre eso.
djangofan
3
Pero, ¿qué pasa si necesito estar seguro de que se llama a algún método estático con argumentos precisos?
elTomato
6
La @PrepareForTestanotación debe ser la clase que llama al método estático, no la clase donde está el método estático.
Hazel Troost
5
@HazelTroost - No, el OP tiene razón. Es la clase que contiene el método estático que debe prepararse para la prueba. Entonces, @PrepareForTest(ClassWithStatics.class)tiene razón.
arry36