1 /*
2 * Copyright 2005-2011 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.springframework.ws.test.server;
18
19 import java.io.IOException;
20
21 import org.springframework.context.ApplicationContext;
22 import org.springframework.util.Assert;
23 import org.springframework.ws.WebServiceMessage;
24 import org.springframework.ws.WebServiceMessageFactory;
25 import org.springframework.ws.context.DefaultMessageContext;
26 import org.springframework.ws.context.MessageContext;
27 import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
28 import org.springframework.ws.soap.server.SoapMessageDispatcher;
29 import org.springframework.ws.test.support.MockStrategiesHelper;
30 import org.springframework.ws.transport.WebServiceMessageReceiver;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34
35 import static org.springframework.ws.test.support.AssertionErrors.fail;
36
37 /**
38 * <strong>Main entry point for server-side Web service testing</strong>. Typically used to test a {@link
39 * org.springframework.ws.server.MessageDispatcher MessageDispatcher} (including its endpoints, mappings, etc) by
40 * creating request messages, and setting up expectations about response messages.
41 * <p/>
42 * The typical usage of this class is:
43 * <ol>
44 * <li>Create a {@code MockWebServiceClient} instance by using {@link #createClient(ApplicationContext)} or
45 * {@link #createClient(WebServiceMessageReceiver, WebServiceMessageFactory)}</li>
46 * <li>Send request messages by calling {@link #sendRequest(RequestCreator)}, possibly by using the default
47 * {@link RequestCreator} implementations provided in {@link RequestCreators} (which can be statically imported).</li>
48 * <li>Set up response expectations by calling {@link ResponseActions#andExpect(ResponseMatcher) andExpect(ResponseMatcher)},
49 * possibly by using the default {@link ResponseMatcher} implementations provided in {@link ResponseMatchers}
50 * (which can be statically imported). Multiple expectations can be set up by chaining {@code andExpect()} calls.</li>
51 * </ol>
52 * Note that because of the 'fluent' API offered by this class (and related classes), you can typically use the Code
53 * Completion features (i.e. ctrl-space) in your IDE to set up the mocks.
54 * <p/>
55 * For example:
56 * <blockquote><pre>
57 * import org.junit.*;
58 * import org.springframework.beans.factory.annotation.Autowired;
59 * import org.springframework.context.ApplicationContext;
60 * import org.springframework.test.context.ContextConfiguration;
61 * import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
62 * import org.springframework.xml.transform.StringSource;
63 * <strong>import org.springframework.ws.test.server.MockWebServiceClient</strong>;
64 * <strong>import static org.springframework.ws.test.server.RequestCreators.*</strong>;
65 * <strong>import static org.springframework.ws.test.server.ResponseMatchers.*</strong>;
66 *
67 * @RunWith(SpringJUnit4ClassRunner.class)
68 * @ContextConfiguration("applicationContext.xml")
69 * public class MyWebServiceIntegrationTest {
70 *
71 * // a standard MessageDispatcherServlet application context, containing endpoints, mappings, etc.
72 * @Autowired
73 * private ApplicationContext applicationContext;
74 *
75 * private MockWebServiceClient mockClient;
76 *
77 * @Before
78 * public void createClient() throws Exception {
79 * <strong>mockClient = MockWebServiceClient.createClient(applicationContext)</strong>;
80 * }
81 *
82 * // test the CustomerCountEndpoint, which is wired up in the application context above
83 * // and handles <customerCount/> messages
84 * @Test
85 * public void customerCountEndpoint() throws Exception {
86 * Source requestPayload = new StringSource(
87 * "<customerCountRequest xmlns='http://springframework.org/spring-ws'>" +
88 * "<customerName>John Doe</customerName>" +
89 * "</customerCountRequest>");
90 * Source expectedResponsePayload = new StringSource(
91 * "<customerCountResponse xmlns='http://springframework.org/spring-ws'>" +
92 * "<customerCount>42</customerCount>" +
93 * "</customerCountResponse>");
94 *
95 * <strong>mockClient.sendMessage(withPayload(requestPayload)).andExpect(payload(expectedResponsePayload))</strong>;
96 * }
97 * }
98 * </pre></blockquote>
99 *
100 * @author Arjen Poutsma
101 * @author Lukas Krecan
102 * @since 2.0
103 */
104 public class MockWebServiceClient {
105
106 private static final Log logger = LogFactory.getLog(MockWebServiceClient.class);
107
108 private final WebServiceMessageReceiver messageReceiver;
109
110 private final WebServiceMessageFactory messageFactory;
111
112 // Constructors
113
114 private MockWebServiceClient(WebServiceMessageReceiver messageReceiver, WebServiceMessageFactory messageFactory) {
115 Assert.notNull(messageReceiver, "'messageReceiver' must not be null");
116 Assert.notNull(messageFactory, "'messageFactory' must not be null");
117 this.messageReceiver = messageReceiver;
118 this.messageFactory = messageFactory;
119 }
120
121 // Factory methods
122
123 /**
124 * Creates a {@code MockWebServiceClient} instance based on the given {@link WebServiceMessageReceiver} and {@link
125 * WebServiceMessageFactory}.
126 *
127 * @param messageReceiver the message receiver, typically a {@link SoapMessageDispatcher}
128 * @param messageFactory the message factory
129 * @return the created client
130 */
131 public static MockWebServiceClient createClient(WebServiceMessageReceiver messageReceiver,
132 WebServiceMessageFactory messageFactory) {
133 return new MockWebServiceClient(messageReceiver, messageFactory);
134 }
135
136 /**
137 * Creates a {@code MockWebServiceClient} instance based on the given {@link ApplicationContext}.
138 *
139 * This factory method works in a similar fashion as the standard
140 * {@link org.springframework.ws.transport.http.MessageDispatcherServlet MessageDispatcherServlet}. That is:
141 * <ul>
142 * <li>If a {@link WebServiceMessageReceiver} is configured in the given application context, it will use that.
143 * If no message receiver is configured, it will create a default {@link SoapMessageDispatcher}.</li>
144 * <li>If a {@link WebServiceMessageFactory} is configured in the given application context, it will use that.
145 * If no message factory is configured, it will create a default {@link SaajSoapMessageFactory}.</li>
146 * </ul>
147 *
148 * @param applicationContext the application context to base the client on
149 * @return the created client
150 */
151 public static MockWebServiceClient createClient(ApplicationContext applicationContext) {
152 Assert.notNull(applicationContext, "'applicationContext' must not be null");
153
154 MockStrategiesHelper strategiesHelper = new MockStrategiesHelper(applicationContext);
155
156 WebServiceMessageReceiver messageReceiver =
157 strategiesHelper.getStrategy(WebServiceMessageReceiver.class, SoapMessageDispatcher.class);
158 WebServiceMessageFactory messageFactory =
159 strategiesHelper.getStrategy(WebServiceMessageFactory.class, SaajSoapMessageFactory.class);
160 return new MockWebServiceClient(messageReceiver, messageFactory);
161 }
162
163 // Sending
164
165 /**
166 * Sends a request message by using the given {@link RequestCreator}. Typically called by using the default request
167 * creators provided by {@link RequestCreators}.
168 *
169 * @param requestCreator the request creator
170 * @return the response actions
171 * @see RequestCreators
172 */
173 public ResponseActions sendRequest(RequestCreator requestCreator) {
174 Assert.notNull(requestCreator, "'requestCreator' must not be null");
175 try {
176 WebServiceMessage request = requestCreator.createRequest(messageFactory);
177 MessageContext messageContext = new DefaultMessageContext(request, messageFactory);
178
179 messageReceiver.receive(messageContext);
180
181 return new MockWebServiceClientResponseActions(messageContext);
182 }
183 catch (Exception ex) {
184 logger.error("Could not send request", ex);
185 fail(ex.getMessage());
186 return null;
187 }
188 }
189
190 // ResponseActions
191
192 private static class MockWebServiceClientResponseActions implements ResponseActions {
193
194 private final MessageContext messageContext;
195
196 private MockWebServiceClientResponseActions(MessageContext messageContext) {
197 Assert.notNull(messageContext, "'messageContext' must not be null");
198 this.messageContext = messageContext;
199 }
200
201 public ResponseActions andExpect(ResponseMatcher responseMatcher) {
202 WebServiceMessage request = messageContext.getRequest();
203 WebServiceMessage response = messageContext.getResponse();
204 if (response == null) {
205 fail("No response received");
206 return null;
207 }
208 try {
209 responseMatcher.match(request, response);
210 return this;
211 }
212 catch (IOException ex) {
213 logger.error("Could not match request", ex);
214 fail(ex.getMessage());
215 return null;
216 }
217 }
218 }
219
220
221 }