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 }