Seetha
Seetha

Reputation: 1059

SoapFault handling with Spring WS client - WebServiceGatewaySupport and WebServiceTemplate

I am trying to write a Spring WS client using WebServiceGatewaySupport. I managed to test the client for a successful request and response. Now I wanted to write test cases for soap faults.

public class MyClient extends WebServiceGatewaySupport {
     public ServiceResponse method(ServiceRequest serviceRequest) {
          return (ServiceResponse) getWebServiceTemplate().marshalSendAndReceive(serviceRequest);
}

@ActiveProfiles("test")
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringTestConfig.class)
@DirtiesContext 
public class MyClientTest {
   @Autowired
   private MyClient myClient;

   private MockWebServiceServer mockServer;

   @Before
    public void createServer() throws Exception {
        mockServer = MockWebServiceServer.createServer(myClient);
    }
}

My question is how do i stub the soap fault response in the mock server, so that my custom FaultMessageResolver will be able to unmarshall soap fault?

I tried couple of things below, but nothing worked.

 // responsePayload being SoapFault wrapped in SoapEnvelope
 mockServer.expect(payload(requestPayload))
            .andRespond(withSoapEnvelope(responsePayload));

 // tried to build error message
 mockServer.expect(payload(requestPayload))
            .andRespond(withError("soap fault string"));

 // tried with Exception
 mockServer.expect(payload(requestPayload))
            .andRespond(withException(new RuntimeException));

Any help is appreciated. Thanks!

Follow Up:

Ok so, withSoapEnvelope(payload) I managed to get the controller to go to my custom MySoapFaultMessageResolver.

public class MyCustomSoapFaultMessageResolver implements FaultMessageResolver     {

private Jaxb2Marshaller jaxb2Marshaller;

@Override
public void resolveFault(WebServiceMessage message) throws IOException {

    if (message instanceof SoapMessage) {
        SoapMessage soapMessage = (SoapMessage) message;

        SoapFaultDetailElement soapFaultDetailElement = (SoapFaultDetailElement) soapMessage.getSoapBody()
            .getFault()
            .getFaultDetail()
            .getDetailEntries()
            .next();
        Source source = soapFaultDetailElement.getSource();
        jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller.setContextPath("com.company.project.schema");
        Object object = jaxb2Marshaller.unmarshal(source);
        if (object instanceof CustomerAlreadyExistsFault) {
            throw new CustomerAlreadyExistsException(soapMessage);
        }
    }
  }
} 

But seriously!!! I had to unmarshall every message and check the instance of it. Being a client I should be thorough with all possible exceptions of the service here, and create custom runtime exceptions and throw it from the resolver. Still at the end, its been caught in WebServiceTemplate and re thrown as just a runtime exception.

Upvotes: 1

Views: 2233

Answers (1)

Heril Muratovic
Heril Muratovic

Reputation: 2018

You could try with something like this:

@Test
public void yourTestMethod() // with no throw here
{
    Source requestPayload = new StringSource("<your request>");
    String errorMessage = "Your error message from WS";

    mockWebServiceServer
        .expect(payload(requestPayload))
        .andRespond(withError(errorMessage));

    YourRequestClass request = new YourRequestClass();
    // TODO: set request properties...

    try {
        yourClient.callMethod(request);    
    } 
    catch (Exception e) {
        assertThat(e.getMessage()).isEqualTo(errorMessage);
    }
    mockWebServiceServer.verify();
}

In this part of code mockWebServiceServer represents the instance of MockWebServiceServer class.

Upvotes: 1

Related Questions