From 83ce414350caa66842312b679666a4ff27d5bbf5 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Tue, 2 Nov 2010 11:13:51 +0000 Subject: [PATCH] SWS-632 - Separated MockWebServiceClient logic into RequestCreators and ResponseMatchers --- .../test/server/AbstractRequestCreator.java | 37 ------ .../ws/test/server/MockWebServiceClient.java | 93 +++++++++------ .../ws/test/server/PayloadRequestCreator.java | 52 --------- .../ws/test/server/RequestCreator.java | 6 +- .../ws/test/server/RequestCreators.java | 107 ++++++++++++++++++ .../ws/test/server/ResponseActions.java | 19 ++-- .../ws/test/server/ResponseMatcher.java | 3 + .../ws/test/server/ResponseMatchers.java | 76 +++++++++++++ .../integration/ServerIntegrationTest.java | 5 +- 9 files changed, 263 insertions(+), 135 deletions(-) delete mode 100644 test/src/main/java/org/springframework/ws/test/server/AbstractRequestCreator.java delete mode 100644 test/src/main/java/org/springframework/ws/test/server/PayloadRequestCreator.java create mode 100644 test/src/main/java/org/springframework/ws/test/server/RequestCreators.java create mode 100644 test/src/main/java/org/springframework/ws/test/server/ResponseMatchers.java diff --git a/test/src/main/java/org/springframework/ws/test/server/AbstractRequestCreator.java b/test/src/main/java/org/springframework/ws/test/server/AbstractRequestCreator.java deleted file mode 100644 index f9f639a6..00000000 --- a/test/src/main/java/org/springframework/ws/test/server/AbstractRequestCreator.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2005-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.test.server; - -import java.io.IOException; - -import org.springframework.ws.WebServiceMessage; -import org.springframework.ws.WebServiceMessageFactory; - -/** - * @author Arjen Poutsma - */ -abstract class AbstractRequestCreator implements RequestCreator { - - public final WebServiceMessage createRequest(WebServiceMessageFactory messageFactory) throws IOException { - WebServiceMessage request = messageFactory.createWebServiceMessage(); - doWithRequest(request); - return request; - } - - protected abstract void doWithRequest(WebServiceMessage request) throws IOException; - -} diff --git a/test/src/main/java/org/springframework/ws/test/server/MockWebServiceClient.java b/test/src/main/java/org/springframework/ws/test/server/MockWebServiceClient.java index 8371c286..56ef6615 100644 --- a/test/src/main/java/org/springframework/ws/test/server/MockWebServiceClient.java +++ b/test/src/main/java/org/springframework/ws/test/server/MockWebServiceClient.java @@ -18,11 +18,9 @@ package org.springframework.ws.test.server; import java.io.IOException; import java.util.Map; -import javax.xml.transform.Source; import org.springframework.beans.factory.BeanInitializationException; import org.springframework.context.ApplicationContext; -import org.springframework.core.io.Resource; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.ws.WebServiceMessage; @@ -31,9 +29,7 @@ import org.springframework.ws.context.DefaultMessageContext; import org.springframework.ws.context.MessageContext; import org.springframework.ws.soap.saaj.SaajSoapMessageFactory; import org.springframework.ws.soap.server.SoapMessageDispatcher; -import org.springframework.ws.test.support.PayloadDiffMatcher; import org.springframework.ws.transport.WebServiceMessageReceiver; -import org.springframework.xml.transform.ResourceSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -41,7 +37,30 @@ import org.apache.commons.logging.LogFactory; import static org.springframework.ws.test.support.Assert.fail; /** + * Main entry point for server-side Web service testing. Typically used to test a {@link + * org.springframework.ws.server.MessageDispatcher MessageDispatcher} (including its endpoints, mappings, etc) by + * creating request messages, and setting up expectations about response messages. + *

+ * The typical usage of this class is: + *

    + *
  1. Create a {@code MockWebServiceClient} instance by using {@link #createClient(ApplicationContext)} or + * {@link #createClient(WebServiceMessageReceiver, WebServiceMessageFactory)}
  2. + *
  3. Send request messages by calling {@link #sendMessage(RequestCreator)}, possibly by using the default + * {@link RequestCreator} implementations provided in {@link RequestCreators} (which can be statically imported).
  4. + *
  5. Set up response expectations by calling {@link ResponseActions#andExpect(ResponseMatcher) andExpect(ResponseMatcher)}, + * possibly by using the default {@link ResponseMatcher} implementations provided in {@link ResponseMatchers} + * (which can be statically imported). Multiple expectations can be set up by chaining {@code andExpect()} calls.
  6. + *
+ * Note that because of the 'fluent' API offered by this class (and related classes), you can typically use the Code + * Completion features (i.e. ctrl-space) in your IDE to set up the mocks. + *

+ * For example: + *

+ * 
+ * * @author Arjen Poutsma + * @author Lukas Krecan + * @since 2.0 */ public class MockWebServiceClient { @@ -51,6 +70,8 @@ public class MockWebServiceClient { private final WebServiceMessageFactory messageFactory; + // Constructors + private MockWebServiceClient(WebServiceMessageReceiver messageReceiver, WebServiceMessageFactory messageFactory) { Assert.notNull(messageReceiver, "'messageReceiver' must not be null"); Assert.notNull(messageFactory, "'messageFactory' must not be null"); @@ -58,15 +79,36 @@ public class MockWebServiceClient { this.messageFactory = messageFactory; } - // Constructors + // Factory methods + /** + * Creates a {@code MockWebServiceClient} instance based on the given {@link WebServiceMessageReceiver} and {@link + * WebServiceMessageFactory}. + * + * @param messageReceiver the message receiver, typically a {@link SoapMessageDispatcher} + * @param messageFactory the message factory + * @return the created client + */ public static MockWebServiceClient createClient(WebServiceMessageReceiver messageReceiver, WebServiceMessageFactory messageFactory) { return new MockWebServiceClient(messageReceiver, messageFactory); } - // Factory methods - + /** + * Creates a {@code MockWebServiceClient} instance based on the given {@link ApplicationContext}. + * + * This factory method works in a similar fashion as the standard + * {@link org.springframework.ws.transport.http.MessageDispatcherServlet MessageDispatcherServlet}. That is: + * + * + * @param applicationContext the application context to base the client on + * @return the created client + */ public static MockWebServiceClient createClient(ApplicationContext applicationContext) { WebServiceMessageReceiver messageReceiver = getMessageReceiver(applicationContext); WebServiceMessageFactory messageFactory = getMessageFactory(applicationContext); @@ -120,6 +162,14 @@ public class MockWebServiceClient { // Sending + /** + * Sends a request message by using the given {@link RequestCreator}. Typically called by using the default request + * creators provided by {@link RequestCreators}. + * + * @param requestCreator the request creator + * @return the response actions + * @see RequestCreators + */ public ResponseActions sendMessage(RequestCreator requestCreator) { Assert.notNull(requestCreator, "'requestCreator' must not be null"); try { @@ -128,7 +178,7 @@ public class MockWebServiceClient { messageReceiver.receive(messageContext); - return new MockWebServiceExchange(messageContext); + return new MockWebServiceClientResponseActions(messageContext); } catch (Exception ex) { fail(ex.getMessage()); @@ -136,21 +186,13 @@ public class MockWebServiceClient { } } - public ResponseActions sendPayload(Source payload) { - Assert.notNull(payload, "'payload' must not be null"); - return sendMessage(new PayloadRequestCreator(payload)); - } + // ResponseActions - public ResponseActions sendPayload(Resource payload) throws IOException { - Assert.notNull(payload, "'payload' must not be null"); - return sendMessage(new PayloadRequestCreator(new ResourceSource(payload))); - } - - private class MockWebServiceExchange implements ResponseActions { + private static class MockWebServiceClientResponseActions implements ResponseActions { private final MessageContext messageContext; - private MockWebServiceExchange(MessageContext messageContext) { + private MockWebServiceClientResponseActions(MessageContext messageContext) { Assert.notNull(messageContext, "'messageContext' must not be null"); this.messageContext = messageContext; } @@ -170,19 +212,6 @@ public class MockWebServiceClient { return null; } } - - public ResponseActions andExpectPayload(Source payload) { - final PayloadDiffMatcher matcher = new PayloadDiffMatcher(payload); - return andExpect(new ResponseMatcher() { - public void match(WebServiceMessage response) throws IOException, AssertionError { - matcher.match(response); - } - }); - } - - public ResponseActions andExpectPayload(Resource payload) throws IOException { - return andExpectPayload(new ResourceSource(payload)); - } } diff --git a/test/src/main/java/org/springframework/ws/test/server/PayloadRequestCreator.java b/test/src/main/java/org/springframework/ws/test/server/PayloadRequestCreator.java deleted file mode 100644 index 1b1b5ab5..00000000 --- a/test/src/main/java/org/springframework/ws/test/server/PayloadRequestCreator.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2005-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.test.server; - -import java.io.IOException; -import javax.xml.transform.Source; -import javax.xml.transform.TransformerException; - -import org.springframework.ws.WebServiceMessage; -import org.springframework.xml.transform.TransformerHelper; - -/** - * Implementation of {@link org.springframework.ws.test.client.ResponseCreator} that writes a {@link - * javax.xml.transform.Source} response. - * - * @author Arjen Poutsma - * @since 2.0 - */ -class PayloadRequestCreator extends AbstractRequestCreator { - - private final Source payload; - - private TransformerHelper transformerHelper = new TransformerHelper(); - - PayloadRequestCreator(Source payload) { - this.payload = payload; - } - - @Override - protected void doWithRequest(WebServiceMessage request) throws IOException { - try { - transformerHelper.transform(payload, request.getPayloadResult()); - } - catch (TransformerException ex) { - throw new AssertionError("Could not transform request payload to message: " + ex.getMessage()); - } - } -} diff --git a/test/src/main/java/org/springframework/ws/test/server/RequestCreator.java b/test/src/main/java/org/springframework/ws/test/server/RequestCreator.java index 622f34fd..72aabfe4 100644 --- a/test/src/main/java/org/springframework/ws/test/server/RequestCreator.java +++ b/test/src/main/java/org/springframework/ws/test/server/RequestCreator.java @@ -22,7 +22,11 @@ import org.springframework.ws.WebServiceMessage; import org.springframework.ws.WebServiceMessageFactory; /** + * Creates request messages. Implementations of this interface are returned by {@link RequestCreators}. + * * @author Arjen Poutsma + * @see RequestCreators + * @since 2.0 */ public interface RequestCreator { @@ -30,7 +34,7 @@ public interface RequestCreator { * Create a request. * * @param messageFactory the message that can be used to create responses - * @throws java.io.IOException in case of I/O errors + * @throws IOException in case of I/O errors */ WebServiceMessage createRequest(WebServiceMessageFactory messageFactory) throws IOException; diff --git a/test/src/main/java/org/springframework/ws/test/server/RequestCreators.java b/test/src/main/java/org/springframework/ws/test/server/RequestCreators.java new file mode 100644 index 00000000..0b35f4c5 --- /dev/null +++ b/test/src/main/java/org/springframework/ws/test/server/RequestCreators.java @@ -0,0 +1,107 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ws.test.server; + +import java.io.IOException; +import javax.xml.transform.Source; +import javax.xml.transform.TransformerException; + +import org.springframework.core.io.Resource; +import org.springframework.util.Assert; +import org.springframework.ws.WebServiceMessage; +import org.springframework.ws.WebServiceMessageFactory; +import org.springframework.xml.transform.ResourceSource; +import org.springframework.xml.transform.TransformerHelper; + +/** + * Factory methods for {@link RequestCreator} classes. Typically used to provide input for {@link + * MockWebServiceClient#sendMessage(RequestCreator)}. + * + * @author Arjen Poutsma + * @since 2.0 + */ +public abstract class RequestCreators { + + private RequestCreators() { + } + + /** + * Create a request with the given {@link Source} XML as payload. + * + * @param payload the request payload + * @return the request creator + */ + public static RequestCreator withPayload(Source payload) { + Assert.notNull(payload, "'payload' must not be null"); + return new PayloadRequestCreator(payload); + } + + /** + * Create a request with the given {@link Resource} XML as payload. + * + * @param payload the request payload + * @return the request creator + */ + public static RequestCreator withPayload(Resource payload) throws IOException { + Assert.notNull(payload, "'payload' must not be null"); + return withPayload(new ResourceSource(payload)); + } + + /** + * Abstract base class for the {@link RequestCreator} interface. + *

+ * Creates a response using the given {@link org.springframework.ws.WebServiceMessageFactory}, and passes it on to + * {@link #doWithRequest(org.springframework.ws.WebServiceMessage)}. + */ + private static abstract class AbstractRequestCreator implements RequestCreator { + + public final WebServiceMessage createRequest(WebServiceMessageFactory messageFactory) throws IOException { + WebServiceMessage request = messageFactory.createWebServiceMessage(); + doWithRequest(request); + return request; + } + + protected abstract void doWithRequest(WebServiceMessage request) throws IOException; + + } + + + /** + * Implementation of {@link RequestCreator} that creates a request based on a {@link javax.xml.transform.Source}. + */ + private static class PayloadRequestCreator extends AbstractRequestCreator { + + private final Source payload; + + private TransformerHelper transformerHelper = new TransformerHelper(); + + PayloadRequestCreator(Source payload) { + this.payload = payload; + } + + @Override + protected void doWithRequest(WebServiceMessage request) throws IOException { + try { + transformerHelper.transform(payload, request.getPayloadResult()); + } + catch (TransformerException ex) { + throw new AssertionError("Could not transform request payload to message: " + ex.getMessage()); + } + } + } + +} diff --git a/test/src/main/java/org/springframework/ws/test/server/ResponseActions.java b/test/src/main/java/org/springframework/ws/test/server/ResponseActions.java index 850d7b41..32bf3686 100644 --- a/test/src/main/java/org/springframework/ws/test/server/ResponseActions.java +++ b/test/src/main/java/org/springframework/ws/test/server/ResponseActions.java @@ -16,26 +16,21 @@ package org.springframework.ws.test.server; -import java.io.IOException; -import javax.xml.transform.Source; - -import org.springframework.core.io.Resource; - /** + * Allows for setting up expectation about response messages. Implementations of this interface are returned by + * {@link MockWebServiceClient#sendMessage(RequestCreator)}. + * * @author Arjen Poutsma + * @since 2.0 */ public interface ResponseActions { /** - * Allows for further expectations to be set on the request. + * Sets up an expectation about the response message. * - * @return the request expectations + * @param responseMatcher the response matcher that defines expectations + * @return an instance of {@link ResponseActions}, to set up further expectations */ ResponseActions andExpect(ResponseMatcher responseMatcher); - ResponseActions andExpectPayload(Source payload); - - ResponseActions andExpectPayload(Resource payload) throws IOException; - - } diff --git a/test/src/main/java/org/springframework/ws/test/server/ResponseMatcher.java b/test/src/main/java/org/springframework/ws/test/server/ResponseMatcher.java index 6272f8aa..588fe593 100644 --- a/test/src/main/java/org/springframework/ws/test/server/ResponseMatcher.java +++ b/test/src/main/java/org/springframework/ws/test/server/ResponseMatcher.java @@ -21,6 +21,9 @@ import java.io.IOException; import org.springframework.ws.WebServiceMessage; /** + * Defines the contract for matching response messages to expectations. Implementations of this interface are returned + * by {@link ResponseMatchers}. + * * @author Arjen Poutsma * @since 2.0 */ diff --git a/test/src/main/java/org/springframework/ws/test/server/ResponseMatchers.java b/test/src/main/java/org/springframework/ws/test/server/ResponseMatchers.java new file mode 100644 index 00000000..4a905624 --- /dev/null +++ b/test/src/main/java/org/springframework/ws/test/server/ResponseMatchers.java @@ -0,0 +1,76 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ws.test.server; + +import java.io.IOException; +import javax.xml.transform.Source; + +import org.springframework.core.io.Resource; +import org.springframework.ws.WebServiceMessage; +import org.springframework.ws.test.support.PayloadDiffMatcher; +import org.springframework.xml.transform.ResourceSource; + +/** + * Factory methods for {@link ResponseMatcher} classes. Typically used to provide input for {@link + * ResponseActions#andExpect(ResponseMatcher)}. + * + * @author Arjen Poutsma + * @since 2.0 + */ +public abstract class ResponseMatchers { + + private ResponseMatchers() { + } + + /** + * Expects any response. + * + * @return the response matcher + */ + public static ResponseMatcher anything() { + return new ResponseMatcher() { + public void match(WebServiceMessage response) { + } + }; + } + + /** + * Expects the given {@link Source} XML payload. + * + * @param payload the XML payload + * @return the response matcher + */ + public static ResponseMatcher payload(Source payload) { + final PayloadDiffMatcher matcher = new PayloadDiffMatcher(payload); + return new ResponseMatcher() { + public void match(WebServiceMessage response) throws IOException { + matcher.match(response); + } + }; + } + + /** + * Expects the given {@link Resource} XML payload. + * + * @param payload the XML payload + * @return the response matcher + */ + public ResponseMatcher payload(Resource payload) throws IOException { + return payload(new ResourceSource(payload)); + } + +} diff --git a/test/src/test/java/org/springframework/ws/test/server/integration/ServerIntegrationTest.java b/test/src/test/java/org/springframework/ws/test/server/integration/ServerIntegrationTest.java index ba468d18..77a89be8 100644 --- a/test/src/test/java/org/springframework/ws/test/server/integration/ServerIntegrationTest.java +++ b/test/src/test/java/org/springframework/ws/test/server/integration/ServerIntegrationTest.java @@ -29,6 +29,9 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import static org.springframework.ws.test.server.RequestCreators.withPayload; +import static org.springframework.ws.test.server.ResponseMatchers.payload; + /** * @author Arjen Poutsma */ @@ -54,7 +57,7 @@ public class ServerIntegrationTest { "" + "42" + ""); - mockClient.sendPayload(requestPayload).andExpectPayload(responsePayload); + mockClient.sendMessage(withPayload(requestPayload)).andExpect(payload(responsePayload)); }