Pregunta

Estoy implementando un cliente que consume un servicio web. Quiero reducir las dependencias y decidí burlarme del servicio web.
Utilizo mockito , tiene la ventaja frente a EasyMock para poder simular clases, no solo interfaces. Pero ese no es el punto.

En mi prueba, tengo este código:

// Mock the required objects
Document mDocument = mock(Document.class);
Element mRootElement = mock(Element.class);
Element mGeonameElement = mock(Element.class);
Element mLatElement = mock(Element.class);
Element mLonElement = mock(Element.class);

// record their behavior
when(mDocument.getRootElement()).thenReturn(mRootElement);
when(mRootElement.getChild("geoname")).thenReturn(mGeonameElement);
when(mGeonameElement.getChild("lat")).thenReturn(mLatElement);
when(mGeonameElement.getChild("lon")).thenReturn(mLonElement);
// A_LOCATION_BEAN is a simple pojo for lat & lon, don't care about it!
when(mLatElement.getText()).thenReturn(
    Float.toString(A_LOCATION_BEAN.getLat()));
when(mLonElement.getText()).thenReturn(
    Float.toString(A_LOCATION_BEAN.getLon()));

// let it work!
GeoLocationFetcher geoLocationFetcher = GeoLocationFetcher
    .getInstance();
LocationBean locationBean = geoLocationFetcher
    .extractGeoLocationFromXml(mDocument);

// verify their behavior
verify(mDocument).getRootElement();
verify(mRootElement).getChild("geoname");
verify(mGeonameElement).getChild("lat");
verify(mGeonameElement).getChild("lon");
verify(mLatElement).getText();
verify(mLonElement).getText();

assertEquals(A_LOCATION_BEAN, locationBean);

Lo que muestra mi código es que yo " micro-prueba " El objeto consumidor. Es como si implementara mi código productivo en mi prueba. Un ejemplo para el resultado xml es London on GeoNames . En mi opinión, es demasiado granular.

Pero, ¿cómo puedo burlarme de un servicio web sin dar cada paso? ¿Debo dejar que el objeto simulado simplemente devuelva un archivo XML?

No se trata del código, sino del enfoque .

Estoy usando JUnit 4.x y Mockito 1.7

¿Fue útil?

Solución

realmente desea burlarse de los resultados devueltos por el servicio web al código que utilizará el resultado. En su código de ejemplo anterior, parece estar burlándose de mDocument, pero realmente quiere pasar una instancia de mDocument que ha sido devuelta desde una instancia simulada de su servicio web y afirmar que el locationBean devuelto por geoLocationFetcher coincide con el valor de A_LOCATION_BEAN.

Otros consejos

Creo que el verdadero problema aquí es que tienes un singleton que llama y crea el servicio web, por lo que es difícil insertar uno falso.

Es posible que tenga que agregar (posiblemente nivel de paquete) acceso a la clase singleton. Por ejemplo, si el constructor se ve algo como

private GeoLocationFactory(WebService service) {
   ...
}

puede hacer que el paquete del constructor se nivele y simplemente crear uno con un servicio web simulado.

Alternativamente, puedes configurar el servicio web agregando un método de establecimiento, aunque no me gustan los Singletons mutables. También, en ese caso, debes recordar desactivar el servicio web después.

Si el servicio web se crea en un método, es posible que tenga que hacer extensible GeoLocationFactory para sustituir el servicio simulado.

También puede buscar eliminar el singleton. Hay artículos en línea y probablemente aquí sobre cómo hacerlo.

La opción más fácil sería burlarse del cliente de servicio web,

when(geoLocationFetcher.extractGeoLocationFromXml(anyString()))
    .thenReturn("<location/>");

Puede modificar el código para leer el xml de respuesta del sistema de archivos.

El código de muestra se puede encontrar aquí: Mocking .NET Servicios web con Mockito

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top