then prevent mock method injectmocks java unit-testing mocking mockito spy

java - prevent - Mockito-espía vs simulacro



mockito spy then return (7)

Ambos se pueden usar para simular métodos o campos. La diferencia es que en simulacro, está creando un simulacro completo o un objeto falso mientras está en espía, existe el objeto real y simplemente está espiando o tropezando con métodos específicos.

Mientras está en objetos espía, por supuesto, dado que es un método real, cuando no está tropezando con el método, llamará al comportamiento del método real. Si desea cambiar y burlarse del método, entonces debe tropezarlo.

Considere el siguiente ejemplo como comparación.

import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Spy; import org.mockito.runners.MockitoJUnitRunner;   import java.util.ArrayList; import java.util.List;   import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.when;   @RunWith(MockitoJUnitRunner.class) public class MockSpy {       @Mock     private List<String> mockList;       @Spy     private List<String> spyList = new ArrayList();       @Test     public void testMockList() {         //by default, calling the methods of mock object will do nothing         mockList.add("test"); Mockito.verify(mockList).add("test"); assertEquals(0, mockList.size());         assertNull(mockList.get(0));     }       @Test     public void testSpyList() {         //spy object will call the real method when not stub         spyList.add("test"); Mockito.verify(spyList).add("test"); assertEquals(1, spyList.size());         assertEquals("test", spyList.get(0));     }       @Test     public void testMockWithStub() {         //try stubbing a method         String expected = "Mock 100";         when(mockList.get(100)).thenReturn(expected);           assertEquals(expected, mockList.get(100));     }       @Test     public void testSpyWithStub() {         //stubbing a spy method will result the same as the mock object         String expected = "Spy 100";         //take note of using doReturn instead of when         doReturn(expected).when(spyList).get(100);           assertEquals(expected, spyList.get(100));     } }

¿Cuándo deberías usar simulacro o espía? Si desea estar seguro y evitar llamar a servicios externos y solo quiere probar la lógica dentro de la unidad, utilice simulacro. Si desea llamar a un servicio externo y realizar llamadas de dependencia real, o simplemente decir, desea ejecutar el programa tal como está y simplemente desactivar métodos específicos, luego use el espía. Entonces esa es la diferencia entre espiar y burlarse de mockito.

Mockito: entiendo que un espía llama a los métodos reales en un objeto, mientras que un simulacro llama a los métodos en el objeto doble. También se deben evitar los espías a menos que haya un olor a código. Sin embargo, ¿cómo funcionan los espías y cuándo debo usarlos? ¿En qué se diferencian de los simulacros?


El mejor lugar para comenzar es probablemente la documentación de mockito .

En una nota general, el simulacro de mockito le permite crear talones.

Crearía un método de código auxiliar si, por ejemplo, ese método realiza una operación costosa. Digamos que obtiene una conexión de base de datos, recupera un valor de la base de datos y lo devuelve a la persona que llama. Obtener la conexión db puede llevar 30 segundos, lo que ralentiza la ejecución de la prueba hasta el punto en que probablemente cambie de contexto (o deje de ejecutar la prueba).

Si la lógica que está probando no le importa la conexión de la base de datos, entonces puede reemplazar ese método con un código auxiliar que devuelve un valor codificado.

El espía mockito le permite verificar si un método llama a otros métodos. Esto puede ser muy útil al intentar obtener el código heredado bajo prueba.

Es útil si está probando un método que funciona a través de los efectos secundarios, entonces usaría un espía falso. Esto delega llamadas al objeto real y le permite verificar la invocación del método, el número de veces invocadas, etc.


He creado un ejemplo ejecutable aquí https://www.surasint.com/mockito-with-spy/

Copio algo de esto aquí.

Si tienes algo como este código:

public void transfer(String fromAccount, String toAccount, double amount){ this.depositeMoneyService = proxyDepositMoneyServiceCreator(); this.withdrawMoneyService = proxyWithdrawMoneyServiceCreator(); withdrawMoneyService.withdraw(fromAccount,amount); depositeMoneyService.deposit(toAccount,amount); } DepositMoneyService proxyDepositMoneyServiceCreator() { return new DepositMoneyService(); } WithdrawMoneyService proxyWithdrawMoneyServiceCreator() { return new WithdrawMoneyService(); }

Es posible que no necesite espía porque simplemente puede burlarse de DepositMoneyService y WithdrawMoneyService.

Pero con algún código heredado, la dependencia está en el código de esta manera:

DepositMoneyService mockDepositMoneyService = mock(DepositMoneyService.class); WithdrawMoneyService mockWithdrawMoneyService = mock(WithdrawMoneyService.class); TransferMoneyService target = spy(new TransferMoneyService()); doReturn(mockDepositMoneyService) .when(target) .proxyDepositMoneyServiceCreator(); doReturn(mockWithdrawMoneyService) .when(target) .proxyWithdrawMoneyServiceCreator();

Sí, puede cambiar al primer código pero luego se cambia la API. Si este método está siendo utilizado por muchos lugares, debe cambiarlos todos.

La alternativa es que puede extraer la dependencia de esta manera:

List<String> mockList = Mockito.mock(ArrayList.class);

Luego puede usar el espía para inyectar la dependencia de esta manera:

List<String> spyList = Mockito.spy(new ArrayList<String>());

Más detalles en el enlace de arriba.


Me gusta la simplicidad de esta recomendación:

  • Si desea estar seguro y evitar llamar a servicios externos y solo quiere probar la lógica dentro de la unidad, utilice simulacro .
  • Si desea llamar a un servicio externo y realizar llamadas de dependencias reales, o simplemente decir, desea ejecutar el programa tal como está y simplemente desactivar métodos específicos, luego use el espía .

Fuente: https://javapointers.com/tutorial/difference-between-spy-and-mock-in-mockito/

Una diferencia común es:

  • Si desea resguardar directamente los métodos de una dependencia, entonces se burlan de esa dependencia.
  • Si desea agrupar los datos en una dependencia para que todos sus métodos devuelvan los valores de prueba que necesita, espíe esa dependencia.


Técnicamente hablando, tanto "simulacros" como "espías" son un tipo especial de "dobles de prueba".

Mockito desafortunadamente hace que la distinción sea extraña.

Un simulacro en mockito es un simulacro normal en otros marcos de simulacro (le permite anular invocaciones; es decir, devolver valores específicos de las llamadas a métodos).

Un espía en mockito es un simulacro parcial en otros frameworks de burla (parte del objeto será burlado y parte usará invocaciones de métodos reales).


TL; versión DR,

Con simulacro , crea una instancia de concha desnuda para usted.

public void transfer( DepositMoneyService depositMoneyService, WithdrawMoneyService withdrawMoneyService, double amount, String fromAccount, String toAccount) { withdrawMoneyService.withdraw(fromAccount,amount); depositMoneyService.deposit(toAccount,amount); }

Con el espía puedes burlarte parcialmente de una instancia existente

public void transfer(String fromAccount, String toAccount, double amount) { this.depositeMoneyService = new DepositMoneyService(); this.withdrawMoneyService = new WithdrawMoneyService(); withdrawMoneyService.withdraw(fromAccount,amount); depositeMoneyService.deposit(toAccount,amount); }

Caso de uso típico para Spy: la clase tiene un constructor parametrizado, primero desea crear el objeto.