¿Cuál es la diferencia entre burlarse y espiar cuando se usa Mockito?
137
¿Cuál sería un caso de uso para un espía Mockito?
Me parece que cada caso de uso de espías se puede manejar con una simulación, usando callRealMethod.
Una diferencia que puedo ver es que si desea que la mayoría de las llamadas a métodos sean reales, guarda algunas líneas de código para usar un simulacro frente a un espía. ¿Es eso o me estoy perdiendo el panorama general?
Finalmente, después de muchos debates internos y discusiones sobre la lista de correo, se agregó un apoyo simulado parcial a Mockito. Anteriormente consideramos simulacros parciales como olores de código. Sin embargo, encontramos un caso de uso legítimo para simulacros parciales.
Antes del lanzamiento 1.8, spy () no producía simulacros parciales reales y era confuso para algunos usuarios. Lea más sobre espionaje: aquí o en javadoc para el método espía (Objeto).
callRealMethod()se introdujo después spy(), pero spy () se dejó allí, por supuesto, para garantizar la compatibilidad con versiones anteriores.
De lo contrario, tienes razón: todos los métodos de un espía son reales a menos que se tropecen. Todos los métodos de un simulacro se topan a menos que callRealMethod()se llame. En general, preferiría usar callRealMethod(), porque no me obliga a usar el doXxx().when()idioma en lugar del tradicionalwhen().thenXxx()
El problema con preferir el simulacro en lugar de espía en estos casos es cuando la clase usa un miembro que no se inyecta en él (sino que se inicializa localmente), y luego se usa por el método "real"; en el simulacro, el miembro se inicializará a su valor predeterminado de Java, lo que podría causar un comportamiento incorrecto o incluso una NullPointerException. La forma de pasar esto es agregar un método "init" y luego "realmente" llamarlo, pero eso me parece un poco exagerado.
Eyal Roth
Del documento: "los espías deben usarse con cuidado y ocasionalmente, por ejemplo, cuando se trata de código heredado". El espacio de prueba de la unidad sufre de demasiadas formas de hacer lo mismo.
gdbj
89
Diferencia entre un espía y un simulacro
Cuando Mockito crea un simulacro, lo hace desde la Clase de un Tipo, no desde una instancia real. El simulacro simplemente crea una instancia de shell básica de la Clase, completamente instrumentada para rastrear las interacciones con ella. Por otro lado, el espía envolverá una instancia existente. Todavía se comportará de la misma manera que la instancia normal: la única diferencia es que también estará instrumentado para rastrear todas las interacciones con él.
En el siguiente ejemplo, creamos un simulacro de la clase ArrayList:
Como puede ver, agregar un elemento a la lista simulada en realidad no agrega nada, solo llama al método sin ningún otro efecto secundario. Un espía, por otro lado, se comportará de manera diferente: en realidad llamará a la implementación real del método add y agregará el elemento a la lista subyacente:
Aquí seguramente podemos decir que se llamó al método interno real del objeto porque cuando llamas al método size () obtienes el tamaño como 1, ¡pero este método size () no se ha burlado! Entonces, ¿de dónde viene 1? El método interno de tamaño real () se llama ya que el tamaño () no se burla (ni se corta) y, por lo tanto, podemos decir que la entrada se agregó al objeto real.
En el primer ejemplo, ¿por qué mockedList.size()regresa 0si ese método tampoco se ha eliminado? ¿Es solo un valor predeterminado dado el tipo de retorno del método?
Mike
@mike: mockedList.size()devuelve un intvalor predeterminado de int0 en Java. Si intenta ejecutar assertEquals(0, mockedList.size());después mockedList.clear();, el resultado permanece igual.
realPK
2
Esta respuesta está bien y simplemente escrita y me ayudó a comprender finalmente la diferencia entre simulacro y espía. Buena esa.
Pesa
38
Si hay un objeto con 8 métodos y tiene una prueba en la que desea llamar a 7 métodos reales y un método único, tiene dos opciones:
Usando un simulacro, tendría que configurarlo invocando 7 callRealMethod y stub one method
Usando un spytienes que configurarlo al aplicar un método
La documentación oficial sobre doCallRealMethodrecomienda el uso de un espía para simulacros parciales.
Consulte también javadoc spy (Object) para obtener más información sobre simulacros parciales. Mockito.spy () es una forma recomendada de crear simulacros parciales. La razón es que garantiza que los métodos reales se invocan contra el objeto construido correctamente porque usted es responsable de construir el objeto pasado al método spy ().
MockEs un doble objeto desnudo. Este objeto tiene las mismas firmas de métodos, pero la realización está vacía y devuelve el valor predeterminado: 0 y nulo
SpyEs un objeto doble clonado. El nuevo objeto se clona en función de un objeto real, pero tiene la posibilidad de burlarse de él
class A {String foo1(){
foo2();return"RealString_1";}String foo2(){return"RealString_2";}void foo3(){
foo4();}void foo4(){}}
Diferencia entre un espía y un simulacro
Cuando Mockito crea un simulacro, lo hace desde la Clase de un Tipo, no desde una instancia real. El simulacro simplemente crea una instancia de shell básica de la Clase, completamente instrumentada para rastrear las interacciones con ella. Por otro lado, el espía envolverá una instancia existente. Todavía se comportará de la misma manera que la instancia normal: la única diferencia es que también estará instrumentado para rastrear todas las interacciones con él.
En el siguiente ejemplo, creamos un simulacro de la clase ArrayList:
Como puede ver, agregar un elemento a la lista simulada en realidad no agrega nada, solo llama al método sin ningún otro efecto secundario. Un espía, por otro lado, se comportará de manera diferente: en realidad llamará a la implementación real del método add y agregará el elemento a la lista subyacente:
Aquí seguramente podemos decir que se llamó al método interno real del objeto porque cuando llamas al método size () obtienes el tamaño como 1, ¡pero este método size () no se ha burlado! Entonces, ¿de dónde viene 1? El método interno de tamaño real () se llama ya que el tamaño () no se burla (ni se corta) y, por lo tanto, podemos decir que la entrada se agregó al objeto real.
Fuente: http://www.baeldung.com/mockito-spy + self notes.
fuente
mockedList.size()
regresa0
si ese método tampoco se ha eliminado? ¿Es solo un valor predeterminado dado el tipo de retorno del método?mockedList.size()
devuelve unint
valor predeterminado deint
0 en Java. Si intenta ejecutarassertEquals(0, mockedList.size());
despuésmockedList.clear();
, el resultado permanece igual.Si hay un objeto con 8 métodos y tiene una prueba en la que desea llamar a 7 métodos reales y un método único, tiene dos opciones:
spy
tienes que configurarlo al aplicar un métodoLa documentación oficial sobre
doCallRealMethod
recomienda el uso de un espía para simulacros parciales.fuente
Spy puede ser útil cuando desea crear pruebas unitarias para código heredado .
He creado un ejemplo ejecutable aquí https://www.surasint.com/mockito-with-spy/ , copio algunos de ellos aquí.
Si tienes algo como este código:
Es posible que no necesite espía porque simplemente puede burlarse de DepositMoneyService y WithdrawMoneyService.
Pero con algunos códigos heredados, la dependencia está en el código de esta manera:
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:
Luego puede usar el espía para inyectar la dependencia de esta manera:
Más detalles en el enlace de arriba.
fuente
Mock
Es un doble objeto desnudo. Este objeto tiene las mismas firmas de métodos, pero la realización está vacía y devuelve el valor predeterminado: 0 y nuloSpy
Es un objeto doble clonado. El nuevo objeto se clona en función de un objeto real, pero tiene la posibilidad de burlarse de él[Prueba de tipos dobles]
fuente