2009-04-27 33 views
6

Tengo una clase que llama a un servicio web existente. Mi clase maneja adecuadamente los resultados válidos, así como las cadenas de fallas generadas por el servicio web. La llamada básica al servicio web se ve más o menos así (aunque esto se simplifica).¿Cómo creo un objeto simulado para Spring WebServiceTemplate?

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 necesito crear algunas pruebas unitarias que prueben todas las condiciones de éxito y falla. No puede llamar al servicio web real, así que esperaba que hubiera objetos falsos disponibles para el lado del cliente de Spring-WS. ¿Alguien sabe de un simulacro de objetos disponibles para la WebServiceTemplate o cualquier clase relacionada? ¿Debería simplemente intentar escribir el mío y modificar mi clase para usar la interfaz WebServiceOperations vs. WebServiceTemplate?

Respuesta

7

Michael la respuesta está muy cerca, pero aquí está el ejemplo que funciona.

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

  1. Modifique el valor almacenado en StreamResult.
  2. Lanza una SoapFaultClientException.

Primero, tenía que darme cuenta de que no puedo burlar WebServiceTemplate con Mockito ya que es una clase concreta (necesita usar EasyMock si esto es esencial). Afortunadamente, la llamada al servicio web, sendSourceAndReceiveToResult, es parte de la interfaz WebServiceOperations. Esto requirió un cambio en mi código para esperar un WebServiceOperations contra 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 una 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.

4

en realidad no sé si existen objetos simulados preconfigurados, pero dudo que estén configurados para todas sus "Condiciones de falla", por lo que puede crear un Spring ApplicationContext especial para su JUnit Test con un sustituto o trabajar con un marco simulacro, no es tan difícil :-)

i utilizado el marco Mock Mockito para el ejemplo (y escribí rápidamente), pero EasyMock o su marco de simulacro preferido debería 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; 
    } 
} 
+0

+1 para Mockito. – CoverosGene

Cuestiones relacionadas