Introducción a PowerMock

1. Información general

Las pruebas unitarias con la ayuda de un marco simulado se han reconocido como una práctica útil durante mucho tiempo, y el marco Mockito, en particular, ha dominado este mercado en los últimos años.

Y para facilitar diseños de código decentes y simplificar la API pública, algunas características deseadas se han omitido intencionalmente. En algunos casos, sin embargo, estas deficiencias obligan a los probadores a escribir código engorroso solo para hacer factible la creación de simulacros.

Aquí es donde entra en juego el marco PowerMock.

PowerMockito es una API de extensión de PowerMock para admitir Mockito. Proporciona capacidades para trabajar con la API de Java Reflection de una manera sencilla para superar los problemas de Mockito, como la falta de capacidad para simular métodos finales, estáticos o privados.

Este tutorial dará una introducción a la API de PowerMockito y cómo se aplica en las pruebas.

2. Preparación para la prueba con PowerMockito

El primer paso para integrar el soporte de PowerMock para Mockito es incluir las siguientes dos dependencias en el archivo POM de Maven:

 org.powermock powermock-module-junit4 1.6.4 test   org.powermock powermock-api-mockito 1.6.4 test 

A continuación, debemos preparar nuestros casos de prueba para trabajar con PowerMockito aplicando las dos anotaciones siguientes:

@RunWith(PowerMockRunner.class) @PrepareForTest(fullyQualifiedNames = "com.baeldung.powermockito.introduction.*")

El elemento FullyQualifiedNames en la anotación @PrepareForTest representa una matriz de nombres completamente calificados de tipos que queremos simular. En este caso, usamos un nombre de paquete con un comodín para decirle a PowerMockito que prepare todos los tipos dentro del paquete com.baeldung.powermockito.introduction para la simulación .

Ahora estamos listos para explotar el poder de PowerMockito .

3. Constructores burlones y métodos finales

En esta sección, demostraremos las formas de obtener una instancia simulada en lugar de una real al crear una instancia de una clase con el operador new , y luego usaremos ese objeto para simular un método final. La clase colaboradora, cuyos constructores y métodos finales serán burlados, se define de la siguiente manera:

public class CollaboratorWithFinalMethods { public final String helloMethod() { return "Hello World!"; } }

Primero, creamos un objeto simulado usando la API de PowerMockito :

CollaboratorWithFinalMethods mock = mock(CollaboratorWithFinalMethods.class);

A continuación, establezca una expectativa que diga que cada vez que se invoca el constructor sin argumentos de esa clase, se debe devolver una instancia simulada en lugar de una real:

whenNew(CollaboratorWithFinalMethods.class).withNoArguments().thenReturn(mock);

Veamos cómo funciona esta simulación de construcción en acción creando una instancia de la clase CollaboratorWithFinalMethods usando su constructor predeterminado, y luego verifiquemos los comportamientos de PowerMock:

CollaboratorWithFinalMethods collaborator = new CollaboratorWithFinalMethods(); verifyNew(CollaboratorWithFinalMethods.class).withNoArguments();

En el siguiente paso, se establece una expectativa para el método final:

when(collaborator.helloMethod()).thenReturn("Hello Baeldung!");

Luego se ejecuta este método:

String welcome = collaborator.helloMethod();

Las siguientes afirmaciones confirman que se ha llamado al método helloMethod en el objeto colaborador y devuelve el valor establecido por la expectativa burlona:

Mockito.verify(collaborator).helloMethod(); assertEquals("Hello Baeldung!", welcome);

Si queremos simular un método final específico en lugar de todos los finales dentro de un objeto, el método Mockito.spy (objeto T) puede ser útil. Esto se ilustra en la sección 5.

4. Burlarse de métodos estáticos

Supongamos que queremos simular métodos estáticos de una clase llamada CollaboratorWithStaticMethods. Esta clase se declara de la siguiente manera:

public class CollaboratorWithStaticMethods { public static String firstMethod(String name) { return "Hello " + name + " !"; } public static String secondMethod() { return "Hello no one!"; } public static String thirdMethod() { return "Hello no one again!"; } }

Para simular estos métodos estáticos, necesitamos registrar la clase adjunta con la API de PowerMockito :

mockStatic(CollaboratorWithStaticMethods.class);

Alternativamente, podemos usar el método Mockito.spy (clase de clase) para simular uno específico como se demuestra en la siguiente sección.

A continuación, se pueden establecer expectativas para definir los valores que los métodos deben devolver cuando se invocan:

when(CollaboratorWithStaticMethods.firstMethod(Mockito.anyString())) .thenReturn("Hello Baeldung!"); when(CollaboratorWithStaticMethods.secondMethod()).thenReturn("Nothing special");

O se puede configurar una excepción para que se lance al llamar al método thirdMethod :

doThrow(new RuntimeException()).when(CollaboratorWithStaticMethods.class); CollaboratorWithStaticMethods.thirdMethod();

Ahora es el momento de ejecutar los dos primeros métodos:

String firstWelcome = CollaboratorWithStaticMethods.firstMethod("Whoever"); String secondWelcome = CollaboratorWithStaticMethods.firstMethod("Whatever");

En lugar de llamar a miembros de la clase real, las invocaciones anteriores se delegan a los métodos del simulacro. Las siguientes afirmaciones demuestran que el simulacro ha entrado en vigor:

assertEquals("Hello Baeldung!", firstWelcome); assertEquals("Hello Baeldung!", secondWelcome);

También podemos verificar el comportamiento de los métodos del simulacro, incluida la cantidad de veces que se invoca un método. En este caso, el firstMethod se ha llamado dos veces, mientras que el secondMethod nunca:

verifyStatic(Mockito.times(2)); CollaboratorWithStaticMethods.firstMethod(Mockito.anyString()); verifyStatic(Mockito.never()); CollaboratorWithStaticMethods.secondMethod();

Nota: El método verifyStatic debe llamarse justo antes de cualquier verificación de método estático para que PowerMockito sepa que la invocación del método sucesivo es lo que debe verificarse.

Por último, el método estático thirdMethod debe lanzar una RuntimeException como se declaró en el simulacro antes. Está validado por el elemento esperado de la anotación @Test :

@Test(expected = RuntimeException.class) public void givenStaticMethods_whenUsingPowerMockito_thenCorrect() { // other methods CollaboratorWithStaticMethods.thirdMethod(); }

5. Burla parcial

En lugar de burlarse de toda una clase, la API de PowerMockito permite burlarse de parte de ella usando el método espía . La siguiente clase se utilizará como colaborador para ilustrar el soporte de PowerMock para simulaciones parciales:

public class CollaboratorForPartialMocking { public static String staticMethod() { return "Hello Baeldung!"; } public final String finalMethod() { return "Hello Baeldung!"; } private String privateMethod() { return "Hello Baeldung!"; } public String privateMethodCaller() { return privateMethod() + " Welcome to the Java world."; } }

Comencemos por burlarnos de un método estático, que se denomina staticMethod en la definición de clase anterior. Primero, use la API PowerMockito para burlarse parcialmente de la clase CollaboratorForPartialMocking y establezca una expectativa para su método estático:

spy(CollaboratorForPartialMocking.class); when(CollaboratorForPartialMocking.staticMethod()).thenReturn("I am a static mock method.");

Luego se ejecuta el método estático:

returnValue = CollaboratorForPartialMocking.staticMethod();

El comportamiento burlón se verifica de la siguiente manera:

verifyStatic(); CollaboratorForPartialMocking.staticMethod();

La siguiente afirmación confirma que en realidad se ha llamado al método simulado comparando el valor de retorno con la expectativa:

assertEquals("I am a static mock method.", returnValue);

Ahora es el momento de pasar a los métodos finales y privados. Para ilustrar la burla parcial de estos métodos, necesitamos crear una instancia de la clase y decirle a la API de PowerMockito que la espíe :

CollaboratorForPartialMocking collaborator = new CollaboratorForPartialMocking(); CollaboratorForPartialMocking mock = spy(collaborator);

The objects created above are used to demonstrating the mocking of both the final and private methods. We will deal with the final method now by setting an expectation and invoke the method:

when(mock.finalMethod()).thenReturn("I am a final mock method."); returnValue = mock.finalMethod();

The behavior of partially mocking that method is proved:

Mockito.verify(mock).finalMethod();

A test verifies that calling the finalMethod method will return a value that matches the expectation:

assertEquals("I am a final mock method.", returnValue);

A similar process is applied to the private method. The main difference is that we cannot directly invoke this method from the test case. Basically, a private method is to be called by other ones from the same class. In the CollaboratorForPartialMocking class, the privateMethod method is to be invoked by the privateMethodCaller method and we will use the latter as a delegate. Let's start with the expectation and invocation:

when(mock, "privateMethod").thenReturn("I am a private mock method."); returnValue = mock.privateMethodCaller();

The mocking of the private method is confirmed:

verifyPrivate(mock).invoke("privateMethod");

The following test makes sure that the return value from invocation of the private method is the same as the expectation:

assertEquals("I am a private mock method. Welcome to the Java world.", returnValue);

6. Conclusion

Este tutorial ha proporcionado una introducción a la API de PowerMockito , demostrando su uso para resolver algunos de los problemas que encuentran los desarrolladores al usar el marco Mockito.

La implementación de estos ejemplos y fragmentos de código se puede encontrar en el proyecto de GitHub vinculado.