Pregunta

Tengo una clase que llama a un servicio web existente. Mi clase controla adecuadamente validez de los resultados, así como cadenas de fallo generadas por el servicio web. La llamada básica para el servicio web se ve algo como esto (aunque esto se simplifica).

public String callWebService(final String inputXml)
{
  String result = null;

  try
  {
    StreamSource input = new StreamSource(new StringReader(inputXml));
    StringWriter output = new StringWriter();

    _webServiceTemplate.sendSourceAndReceiveToResult(_serviceUri, input, new StreamResult(output));

    result = output.toString();
  }
  catch (SoapFaultClientException ex)
  {
    result = ex.getFaultStringOrReason();
  }

  return result;
}

Ahora tengo que crear algunas pruebas unitarias que ponen a prueba todas las condiciones de éxito y fracaso. No se puede llamar al servicio web real, así que estaba esperando había objetos simulados para el lado del cliente de la primavera-WS. ¿Alguien sabe de un objetos simulados para la WebServiceTemplate o cualesquiera clases relacionadas? ¿Debo intentar escribir mi propia y modificar mi clase para utilizar la interfaz WebServiceOperations vs WebServiceTemplate?

¿Fue útil?

Solución

La respuesta de Michael está muy cerca, pero aquí es el ejemplo que funciona.

Ya utilizo Mockito para mis pruebas de unidad, así que estoy familiarizado con la biblioteca. Sin embargo, a diferencia de mi experiencia previa con Mockito, simplemente burlarse de la devolución de resultado no ayuda. Necesito hacer dos cosas para poner a prueba todos los casos de uso:

  1. Modificar el valor almacenado en la StreamResult.
  2. Lanza una SoapFaultClientException.

En primer lugar, tenía que darse cuenta de que no puedo burlo WebServiceTemplate con Mockito ya que es una clase concreta (es necesario utilizar EasyMock si esto es esencial). Por suerte, la llamada al servicio web, sendSourceAndReceiveToResult, es parte de la interfaz WebServiceOperations. Esto requiere un cambio en mi código para esperar una WebServiceOperations vs un WebServiceTemplate.

El siguiente código apoya el primer caso de uso donde un resultado se devuelve en el parámetro StreamResult:

private WebServiceOperations getMockWebServiceOperations(final String resultXml)
{
  WebServiceOperations mockObj = Mockito.mock(WebServiceOperations.class);

  doAnswer(new Answer()
  {
    public Object answer(InvocationOnMock invocation)
    {
      try
      {
        Object[] args = invocation.getArguments();
        StreamResult result = (StreamResult)args[2];
        Writer output = result.getWriter();
        output.write(resultXml);
      }
      catch (IOException e)
      {
        e.printStackTrace();
      }

      return null;
    }
  }).when(mockObj).sendSourceAndReceiveToResult(anyString(), any(StreamSource.class), any(StreamResult.class));

  return mockObj;
}

El soporte para el segundo caso de uso es similar, pero requiere el lanzamiento de una excepción. El siguiente código crea un SoapFaultClientException que contiene el faultString. El faultCode es utilizado por el código que estoy probando que se ocupa de la solicitud de servicio web:

private WebServiceOperations getMockWebServiceOperations(final String faultString)
{
  WebServiceOperations mockObj = Mockito.mock(WebServiceOperations.class);

  SoapFault soapFault = Mockito.mock(SoapFault.class);
  when(soapFault.getFaultStringOrReason()).thenReturn(faultString);

  SoapBody soapBody = Mockito.mock(SoapBody.class);
  when(soapBody.getFault()).thenReturn(soapFault);

  SoapMessage soapMsg = Mockito.mock(SoapMessage.class);
  when(soapMsg.getSoapBody()).thenReturn(soapBody);

  doThrow(new SoapFaultClientException(soapMsg)).when(mockObj).sendSourceAndReceiveToResult(anyString(), any(StreamSource.class), any(StreamResult.class));

  return mockObj;
}

Más de código puede ser necesaria para ambos casos de uso, pero trabajan para mis propósitos.

Otros consejos

En realidad no sé si existen objetos preconfigurados Mock, pero dudo que haya configurado por toda su "fracaso Condiciones", por lo que puede crear una primavera Application Context especial para su prueba JUnit con un sustituto o trabajar con una maqueta marco, que no es tan difícil: -)

i utilizado el Mockito marco Mock para el ejemplo (y tecleado rápidamente), pero EasyMock o su marco preferido simulacro debe hacerlo así

package org.foo.bar
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;

public class WebserviceTemplateMockTest {

    private WhateverTheInterfaceIs webServiceTemplate;
    private TestClassInterface testClass;
    private final String inputXml = "bar";


    @Test
    public void testClient(){
        // 
        assertTrue("foo".equals(testClass.callWebService(inputXml));
    }

    /**
     * Create Webservice Mock.
     */
    @Before
    public void createMock() {
        // create Mock
        webServiceTemplate = mock(WhateverTheInterfaceIs.class);
        // like inputXml you need to create testData for Uri etc.
        // 'result' should be the needed result data to produce the
        // real result of testClass.callWebService(...)
        when(webServiceTemplate.sendSourceAndReceiveToResult(Uri, inputXml, new StreamResult(output))).thenReturn(result);
        // or return other things, e.g.
        // .thenThrow(new FoobarException());
        // see mockito documentation for more possibilities
        // Setup Testclass
        TestClassImpl temp = new TestClassImpl();
        temp.setWebServiceTemplate(generatedClient);
        testClass = temp;
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top