without mockitojunitrunner mock method java unit-testing mockito static-methods

java - mockitojunitrunner - powermock static method



Cómo verificar el método de vacío estático ha sido llamado con power mockito (2)

Estoy usando lo siguiente.

Powermock-mockito 1.5.12 Mockito 1.95 junit 4.11

Aquí está mi clase utils

public void InternalUtils { public static void sendEmail(String from, String[] to, String msg, String body) { } }

aquí está la esencia de la clase bajo prueba:

public class InternalService { public void processOrder(Order order) { if (order.isSuccessful()) { InternalUtils.sendEmail(...); } } }

Y aquí está la prueba:

@PrepareForTest({InternalUtils.class}) @RunWith(PowerMockRunner.class) public class InternalService { public void verifyEmailSend() { mockStatic(Internalutils.class); doNothing().when(InternalUtils, "sendEmail", anyString(), any(String.class), anyString(), anyString()); Order order = mock(Order.class); when(order.isSuccessful()).thenReturn(true); InternalService is = new InternalService(); verifyStatic(times(1)); is.processOrder(order); } }

La prueba anterior falla. El modo de verificación dado es ninguno, pero de acuerdo con el código, si el pedido es exitoso, debe enviarse el correo electrónico.


Si la respuesta anterior es ampliamente aceptada y está bien documentada, he encontrado algunas de las razones para publicar mi respuesta aquí:

doNothing().when(InternalUtils.class); //This is the preferred way //to mock static void methods. InternalUtils.sendEmail(anyString(), anyString(), anyString(), anyString());

Aquí, no entiendo por qué estamos llamando InternalUtils.sendEmail nosotros mismos. Explicaré en mi código por qué no necesitamos hacer eso.

mockStatic(Internalutils.class);

Entonces, nos hemos burlado de la clase, lo cual está bien. Ahora, veamos cómo necesitamos verificar el método sendEmail (/..../).

@PrepareForTest({InternalService.InternalUtils.class}) @RunWith(PowerMockRunner.class) public class InternalServiceTest { @Mock private InternalService.Order order; private InternalService internalService; @Before public void setup() { MockitoAnnotations.initMocks(this); internalService = new InternalService(); } @Test public void processOrder() throws Exception { Mockito.when(order.isSuccessful()).thenReturn(true); PowerMockito.mockStatic(InternalService.InternalUtils.class); internalService.processOrder(order); PowerMockito.verifyStatic(times(1)); InternalService.InternalUtils.sendEmail(anyString(), any(String[].class), anyString(), anyString()); } }

Estas dos líneas es donde está la magia, First Line le dice al framework PowerMockito que necesita verificar la clase de la que se burló estáticamente. ¿Pero qué método necesita verificar? La segunda línea indica qué método necesita verificar.

PowerMockito.verifyStatic(times(1)); InternalService.InternalUtils.sendEmail(anyString(), any(String[].class), anyString(), anyString());

Este es el código de mi clase, sendEmail api dos veces.

public class InternalService { public void processOrder(Order order) { if (order.isSuccessful()) { InternalUtils.sendEmail("", new String[1], "", ""); InternalUtils.sendEmail("", new String[1], "", ""); } } public static class InternalUtils{ public static void sendEmail(String from, String[] to, String msg, String body){ } } public class Order{ public boolean isSuccessful(){ return true; } } }

Como está llamando dos veces, solo necesita cambiar la verificación (veces (2)) ... eso es todo.


Si se está burlando del comportamiento (con algo como doNothing() ) realmente no debería haber ninguna necesidad de llamar para verify*() . Dicho esto, aquí está mi puñalada para volver a escribir su método de prueba:

@PrepareForTest({InternalUtils.class}) @RunWith(PowerMockRunner.class) public class InternalServiceTest { //Note the renaming of the test class. public void testProcessOrder() { //Variables InternalService is = new InternalService(); Order order = mock(Order.class); //Mock Behavior when(order.isSuccessful()).thenReturn(true); mockStatic(Internalutils.class); doNothing().when(InternalUtils.class); //This is the preferred way //to mock static void methods. InternalUtils.sendEmail(anyString(), anyString(), anyString(), anyString()); //Execute is.processOrder(order); //Verify verifyStatic(InternalUtils.class); //Similar to how you mock static methods //this is how you verify them. InternalUtils.sendEmail(anyString(), anyString(), anyString(), anyString()); } }

Agrupé en cuatro secciones para resaltar mejor lo que está sucediendo:

1. Variables

Elijo declarar aquí cualquier variable de instancia / argumento de método / simulacro de colaboradores. Si es algo que se usa en múltiples pruebas, considere convertirlo en una variable de instancia de la clase de prueba.

2. Comportamiento simulado

Aquí es donde defines el comportamiento de todos tus simulacros. Está configurando los valores de retorno y las expectativas aquí, antes de ejecutar el código bajo prueba. En términos generales, si establece el comportamiento simulado aquí, no necesitará verificar el comportamiento más adelante.

3. Ejecutar

Nada lujoso aquí; esto simplemente inicia el código que se está probando. Me gusta darle su propia sección para llamar la atención.

4. Verificar

Esto es cuando llamas a cualquier método que comience con verify o assert . Después de que termine la prueba, compruebas que las cosas que querías suceder realmente ocurrieron. Ese es el mayor error que veo con su método de prueba; Intentó verificar la llamada al método antes de que se le diera la oportunidad de ejecutar. En segundo lugar, nunca especificó qué método estático quería verificar.

Notas adicionales

Esto es principalmente preferencia personal de mi parte. Hay un cierto orden en el que debe hacer las cosas, pero dentro de cada agrupación hay un pequeño margen de maniobra. Esto me ayuda a separar rápidamente lo que está sucediendo.

También recomiendo examinar los ejemplos en los siguientes sitios, ya que son muy sólidos y pueden ayudar con la mayoría de los casos que necesitará: