payload source of response with spring ws MockWebServiceClient
I'm using spring-ws 2.0.2 and spring-ws-test to run integration tests of my SOAP server. I'm using an approach exactly like that from http://static.springsource.org/spring-ws/site/apidocs/org/springframework/ws/test/server/MockWebServiceClient.html
Here's the code I'm running with the expected response XML omitted for brevity and because it's not relevant to the question.
I'd like to be able to see the xml in the response payload but can't figure out how to get access to it. If I set a breakpoint after response is set and inspect it I can see that it has a private messageContext.response of type SaajSoapMessage but I can't figure out how to access it or if there's a better way to see the response XML.
package com.example.integration;
import static org.springframework.ws.test.server.RequestCreators.*;
import static org.springframework.ws.test.server.ResponseMatchers.*;
import static org.testng.AssertJUnit.*;
import javax.xml.transform.Source;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.ws.test.server.MockWebServiceClient;
import org.springframework.ws.test.server.ResponseActions;
import org.springframework.xml.transform.StringSource;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@ContextConfiguration(locations={"/transaction-test-context.xml", "/spring-web-services-servlet.xml"})
public class BaseWebServiceIntegrationTest {
@Autowired
private ApplicationContext applicationContext;
private MockWebServiceClient mockClient;
@BeforeClass(groups="integration")
public void createClient() {
assertNotNull("expected applicationContext to be non-null", applicationContext);
mockClient = MockWebServiceClient.createClient(applicationContext);
}
@Test(groups="integration")
public void proofOfConcept() {
assertNotNull("expected mockClient to be non-null", mockClient);
Source requestPayload = new StringSource(
"<s0:ListDevicesRequest " +
"xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding/' " +
"xmlns:xs='http://www.w3.org/2001/XMLSchema' " +
"xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' " +
"xmlns:s0='urn:com:example:xmlschema:service:v1.1:DeviceManager.xsd'>" +
"<s0:MacID>66:bb:be:ee:00:00:01:00</s0:MacID>" +
"</s0:ListDevicesRequest>"
);
Source responsePayload = new StringSource("<!-- response omitted for the post, not relevant -->");
ResponseActions response = mockClient.sendRequest(withPayload(requestPayload));
response.andExpect(noFault())
.andExpect(payload(responsePayload));
}
}
edited to add the application context file as requested. we have a few but the one below is the soap-specific one.
<?xml version="1.0"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<sec:global-method-security pre-post-annotations="disabled" jsr250-annotations="disabled" />
<tx:annotation-driven/>
<context:component-scan base-package="com.example.integration"/>
<context:component-scan base-package="com.example.signal"/>
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean id="faultService" class="com.example.webservice.fault.FaultService"/>
<bean id="soapDeviceService" class="com.example.webservice.device.SoapDeviceServiceImpl"/>
<!-- 1.1 Endpoints -->
<bean id="deviceManagerEndpoint_v1_1" class="com.example.webservice.spring.DeviceManagerEndpoint">
<property name="soapDeviceService" ref="soapDeviceService"/>
</bean>
<bean class="com.example.webservice.spring.PayloadMethodMarshallingEndpointAdapter">
<property name="marshaller" ref="marshaller"/>
<property name="unmarshaller" ref="marshaller"/>
</bean>
<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="mtomEnabled" value="false"/>
<property name="contextPath" value="com.example.xmlschema.service.v1_0.devicemanager"/>
</bean>
<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping">
<property name="interceptors">
<list>
<bean class="com.example.webservice.interceptor.LoggingInterceptor"/>开发者_如何学编程;
<ref bean="validatingInterceptor"/>
</list>
</property>
</bean>
<bean id="validatingInterceptor" class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
<property name="schemas">
<list>
<value>/WEB-INF/wsdl/*Types_v*.xsd</value>
</list>
</property>
<property name="validateRequest" value="true"/>
<property name="validateResponse" value="true"/>
</bean>
<bean class="com.example.webservice.spring.SpringWebserviceFaultMappingExceptionResolver">
<property name="order" value="1"/>
<property name="marshaller" ref="marshaller"/>
</bean>
</beans>
Ok, 4 years too late, but here is my answer, which I am both proud and ashamed of :-
.andExpect(
new ResponseMatcher()
{
@Override
public void match(WebServiceMessage request, WebServiceMessage response)
throws IOException, AssertionError
{
response.writeTo(System.out);
}
})
And since Java 8:
.andExpect((request, response) -> response.writeTo(System.out))
You could install a PayloadLoggingInterceptor in your spring-ws context which will by default log all request and response payloads. Configure it like this:
<sws:interceptors>
<bean class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor"/>
</sws:interceptors>
Check out the springsource docs for more info here
Configure log4j and add configuration in log4j to show the spring classes logs. The logs will show the order in which spring classes are called and also the request and response sent.
<logger name="org.springframework.ws" additivity="false">
<level value="DEBUG#org.tiaa.infra.logging.TiaaLevel" />
<appender-ref ref="DailyRollingFileAppender"/>
</logger>
+1 for @NeilStevens solution... It's never too late!. Thanks :-) Here is a slight refactor to print stuff out to a sf4j logger and use the magic of static imports...:
import static SomeTestClass.ResponseOutputMatcher.printResponse;
public class SomeTestClass {
private static final Logger LOG = LoggerFactory.getLogger(SomeTestClass.class);
@Test
public void someTest() {
mockClient.sendRequest(...)
.andExpect(printResponse(LOG))
.andExpect(noFault());
}
@RequiredArgsConstructor
public static class ResponseOutputMatcher implements ResponseMatcher {
private final Logger logger;
public ResponseOutputMatcher() {
this(LoggerFactory.getLogger(ResponseOutputMatcher.class));
}
@Override
public void match(WebServiceMessage request, WebServiceMessage response) throws IOException, AssertionError {
ByteArrayOutputStream out = new ByteArrayOutputStream();
response.writeTo(out);
logger.info(format("Received payload response:\n%s\n%s\n%s", repeat(">", 80), out.toString(), repeat("_", 80)));
}
public static ResponseMatcher printResponse(Logger logger) {
return new ResponseOutputMatcher(logger);
}
}
精彩评论