java - ventana - Mockito: tratar de espiar el método es llamar al método original
crear una ventana dentro de otra ventana en java (7)
En mi caso, utilizando Mockito 2.0, tuve que cambiar todos los parámetros any () a nullable () para apagar la llamada real.
Estoy usando Mockito 1.9.0. Quiero simular el comportamiento de un solo método de una clase en una prueba JUnit, así que tengo
final MyClass myClassSpy = Mockito.spy(myInstance);
Mockito.when(myClassSpy.method1()).thenReturn(myResults);
El problema es que, en la segunda línea, a myClassSpy.method1()
realmente se le llama, lo que resulta en una excepción. La única razón por la que estoy usando simulacros es para que luego, cuando se myClassSpy.method1()
se llamará al método real y se myResults
objeto myResults
.
MyClass
es una interfaz y myInstance
es una implementación de eso, si eso importa.
¿Qué necesito hacer para corregir este comportamiento de espionaje?
He encontrado otra razón para que el espía llame al método original.
Alguien tuvo la idea de burlarse de una clase final
, y descubrió acerca de MockMaker
:
Como esto funciona de manera diferente a nuestro mecanismo actual y este tiene limitaciones diferentes y como queremos recopilar experiencia y comentarios de los usuarios, esta función tenía que activarse explícitamente para estar disponible; se puede hacer a través del mecanismo de extensión mockito creando el archivo
src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
contiene una sola línea:mock-maker-inline
Después de fusionar y traer ese archivo a mi máquina, mis pruebas fallaron.
Solo tuve que eliminar la línea (o el archivo) y spy()
funcionó.
Mi caso fue diferente de la respuesta aceptada. Estaba intentando burlar un método de paquete privado para una instancia que no vivía en ese paquete
package common;
public class Animal {
void packageProtected();
}
package instances;
class Dog extends Animal { }
y las clases de prueba
package common;
public abstract class AnimalTest<T extends Animal> {
@Before
setup(){
doNothing().when(getInstance()).packageProtected();
}
abstract T getInstance();
}
package instances;
class DogTest extends AnimalTest<Dog> {
Dog getInstance(){
return spy(new Dog());
}
@Test
public void myTest(){}
}
La compilación es correcta, pero cuando intenta configurar la prueba, invoca el método real en su lugar.
Declarar el método protegido o resolver el problema públicamente , aunque no es una solución limpia.
Otro escenario posible que puede causar problemas con los espías es cuando está probando frijoles de primavera (con el marco de prueba de primavera) o algún otro marco que esté procesando sus objetos durante la prueba .
Ejemplo
@Autowired
private MonitoringDocumentsRepository repository
void test(){
repository = Mockito.spy(repository)
Mockito.doReturn(docs1, docs2)
.when(repository).findMonitoringDocuments(Mockito.nullable(MonitoringDocumentSearchRequest.class));
}
En el código anterior, tanto Spring como Mockito intentarán usar su objeto MonitoringDocumentsRepository, pero Spring será el primero, lo que provocará la llamada real del método findMonitoringDocuments. Si depuramos nuestro código justo después de colocar un objeto espía en el repositorio, se verá así dentro del depurador:
repository = MonitoringDocumentsRepository$$EnhancerBySpringCGLIB$$MockitoMock$
@SpyBean al rescate
Si, en @Autowired
anotación @Autowired
@SpyBean
anotación @SpyBean
, resolveremos el problema anterior, la anotación SpyBean también inyectará un objeto de repositorio, pero primero será procesado por Mockito y se verá así dentro del depurador
repository = MonitoringDocumentsRepository$$MockitoMock$$EnhancerBySpringCGLIB$
Y aquí está el código:
@SpyBean
private MonitoringDocumentsRepository repository
void test(){
Mockito.doReturn(docs1, docs2)
.when(repository).findMonitoringDocuments(Mockito.nullable(MonitoringDocumentSearchRequest.class));
}
Permítanme citar la documentación oficial :
Importante gotcha en espiar objetos reales!
A veces es imposible usar cuando (Objeto) para espiar a espías. Ejemplo:
List list = new LinkedList();
List spy = spy(list);
// Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
when(spy.get(0)).thenReturn("foo");
// You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);
En tu caso va algo como:
doReturn(resulstIWant).when(myClassSpy).method1();
Una forma de asegurarse de que no se llame a un método de una clase es anular el método con un dummy.
WebFormCreatorActivity activity = spy(new WebFormCreatorActivity(clientFactory) {//spy(new WebFormCreatorActivity(clientFactory));
@Override
public void select(TreeItem i) {
log.debug("SELECT");
};
});
¡La respuesta de Tomasz Nurkiewicz parece no contar toda la historia!
NB versión de Mockito: 1.10.19.
Soy muy nuevo en Mockito, así que no puedo explicar el siguiente comportamiento: si hay un experto que pueda mejorar esta respuesta, siéntase libre.
El método en cuestión aquí, getContentStringValue
, NO es final
y NO static
.
Esta línea llama al método original getContentStringValue
:
doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), isA( ScoreDoc.class ));
Esta línea no llama al método original getContentStringValue
:
doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), any( ScoreDoc.class ));
Por razones que no puedo responder, el uso de isA()
hace que el comportamiento previsto (?) "No llamar al método" de doReturn
falle.
Veamos las firmas de métodos involucradas aquí: ambos son métodos static
de Matchers
. El Javadoc dice que ambos devuelven el null
, lo cual es un poco difícil de entender en sí mismo. Presumiblemente, el objeto de Class
pasado como parámetro se examina, pero el resultado nunca se calcula o se descarta. Dado que null
puede significar cualquier clase y que espera que no se llame al método isA( ... )
, no podrían las firmas de isA( ... )
y any( ... )
simplemente devolver null
lugar de un parámetro genérico * <T>
?
De todas formas:
public static <T> T isA(java.lang.Class<T> clazz)
public static <T> T any(java.lang.Class<T> clazz)
La documentación de la API no da ninguna pista sobre esto. También parece decir que la necesidad de tal comportamiento de "no llamar método" es "muy rara". Personalmente uso esta técnica todo el tiempo : por lo general, me parece que la burla involucra algunas líneas que "configuran la escena" ... seguidas de un método que luego "reproduce" la escena en el contexto simulado en el que has organizado ... . y mientras configuras el escenario y los accesorios, lo último que quieres es que los actores entren en el escenario a la izquierda y comiencen a mostrar sus corazones ...
Pero esto va más allá de mi grado de pago ... Invito explicaciones de cualquier sumo sacerdote de Mockito que pase ...
* ¿Es "parámetro genérico" el término correcto?