From 2e4f38f6af49637f2ff5f651944aef35a049c60a Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 23 Dec 2013 14:02:48 -0500 Subject: [PATCH] Introduce AbstractMockMvcBuilder class This change splits out an abstract base class from DefaultMockMvcBuilder with StandaloneMockMvcBuilder switching to extend the new abstract class (rather than DefaultMockMvcBuilder). Issue: SPR-11238 --- .../web/servlet/MockMvcBuilderSupport.java | 3 +- .../servlet/setup/AbstractMockMvcBuilder.java | 203 ++++++++++++++++++ .../servlet/setup/DefaultMockMvcBuilder.java | 165 +------------- .../web/servlet/setup/MockMvcBuilders.java | 4 +- .../setup/StandaloneMockMvcBuilder.java | 41 ++-- .../setup/DefaultMockMvcBuilderTests.java | 2 +- .../setup/StandaloneMockMvcBuilderTests.java | 23 +- 7 files changed, 253 insertions(+), 188 deletions(-) create mode 100644 spring-test/src/main/java/org/springframework/test/web/servlet/setup/AbstractMockMvcBuilder.java diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/MockMvcBuilderSupport.java b/spring-test/src/main/java/org/springframework/test/web/servlet/MockMvcBuilderSupport.java index 925c6b0e9e8..19f1a934a4c 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/MockMvcBuilderSupport.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/MockMvcBuilderSupport.java @@ -42,7 +42,8 @@ public abstract class MockMvcBuilderSupport { protected final MockMvc createMockMvc(Filter[] filters, MockServletConfig servletConfig, WebApplicationContext webAppContext, RequestBuilder defaultRequestBuilder, - List globalResultMatchers, List globalResultHandlers, Boolean dispatchOptions) { + List globalResultMatchers, List globalResultHandlers, + Boolean dispatchOptions) { ServletContext servletContext = webAppContext.getServletContext(); diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/AbstractMockMvcBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/AbstractMockMvcBuilder.java new file mode 100644 index 00000000000..67d86ca76ae --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/AbstractMockMvcBuilder.java @@ -0,0 +1,203 @@ +/* + * Copyright 2002-2013 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.test.web.servlet.setup; + +import org.springframework.mock.web.MockServletConfig; +import org.springframework.test.web.servlet.*; +import org.springframework.util.Assert; +import org.springframework.web.context.WebApplicationContext; + +import javax.servlet.Filter; +import javax.servlet.ServletContext; +import java.util.ArrayList; +import java.util.List; + +/** + * An abstract implementation of {@link org.springframework.test.web.servlet.MockMvcBuilder} + * with common methods for configuring filters, default request properties, global + * expectations and global result actions. + *

+ * Sub-classes can use different strategies to prepare a WebApplicationContext to + * pass to the DispatcherServlet. + * + * @author Rossen Stoyanchev + * @since 4.0 + */ +public abstract class AbstractMockMvcBuilder> + extends MockMvcBuilderSupport implements MockMvcBuilder { + + private List filters = new ArrayList(); + + private RequestBuilder defaultRequestBuilder; + + private final List globalResultMatchers = new ArrayList(); + + private final List globalResultHandlers = new ArrayList(); + + private Boolean dispatchOptions = Boolean.FALSE; + + + + /** + * Add filters mapped to any request (i.e. "/*"). For example: + * + *

+	 * mockMvcBuilder.addFilters(springSecurityFilterChain);
+	 * 
+ * + *

is the equivalent of the following web.xml configuration: + * + *

+	 * <filter-mapping>
+	 *     <filter-name>springSecurityFilterChain</filter-name>
+	 *     <url-pattern>/*</url-pattern>
+	 * </filter-mapping>
+	 * 
+ * + *

Filters will be invoked in the order in which they are provided. + * + * @param filters the filters to add + */ + @SuppressWarnings("unchecked") + public final T addFilters(Filter... filters) { + Assert.notNull(filters, "filters cannot be null"); + + for(Filter f : filters) { + Assert.notNull(f, "filters cannot contain null values"); + this.filters.add(f); + } + return (T) this; + } + + /** + * Add a filter mapped to a specific set of patterns. For example: + * + *

+	 * mockMvcBuilder.addFilters(myResourceFilter, "/resources/*");
+	 * 
+ * + *

is the equivalent of: + * + *

+	 * <filter-mapping>
+	 *     <filter-name>myResourceFilter</filter-name>
+	 *     <url-pattern>/resources/*</url-pattern>
+	 * </filter-mapping>
+	 * 
+ * + *

Filters will be invoked in the order in which they are provided. + * + * @param filter the filter to add + * @param urlPatterns URL patterns to map to; if empty, "/*" is used by default + */ + @SuppressWarnings("unchecked") + public final T addFilter(Filter filter, String... urlPatterns) { + + Assert.notNull(filter, "filter cannot be null"); + Assert.notNull(urlPatterns, "urlPatterns cannot be null"); + + if(urlPatterns.length > 0) { + filter = new PatternMappingFilterProxy(filter, urlPatterns); + } + + this.filters.add(filter); + return (T) this; + } + + /** + * Define default request properties that should be merged into all + * performed requests. In effect this provides a mechanism for defining + * common initialization for all requests such as the content type, request + * parameters, session attributes, and any other request property. + * + *

Properties specified at the time of performing a request override the + * default properties defined here. + * + * @param requestBuilder a RequestBuilder; see static factory methods in + * {@link org.springframework.test.web.servlet.request.MockMvcRequestBuilders} + * . + */ + @SuppressWarnings("unchecked") + public final T defaultRequest(RequestBuilder requestBuilder) { + this.defaultRequestBuilder = requestBuilder; + return (T) this; + } + + /** + * Define a global expectation that should always be applied to + * every response. For example, status code 200 (OK), content type + * {@code "application/json"}, etc. + * + * @param resultMatcher a ResultMatcher; see static factory methods in + * {@link org.springframework.test.web.servlet.result.MockMvcResultMatchers} + */ + @SuppressWarnings("unchecked") + public final T alwaysExpect(ResultMatcher resultMatcher) { + this.globalResultMatchers.add(resultMatcher); + return (T) this; + } + + /** + * Define a global action that should always be applied to every + * response. For example, writing detailed information about the performed + * request and resulting response to {@code System.out}. + * + * @param resultHandler a ResultHandler; see static factory methods in + * {@link org.springframework.test.web.servlet.result.MockMvcResultHandlers} + */ + @SuppressWarnings("unchecked") + public final T alwaysDo(ResultHandler resultHandler) { + this.globalResultHandlers.add(resultHandler); + return (T) this; + } + + /** + * Should the {@link org.springframework.web.servlet.DispatcherServlet} dispatch OPTIONS request to controllers. + * @param dispatchOptions + * @see org.springframework.web.servlet.DispatcherServlet#setDispatchOptionsRequest(boolean) + */ + @SuppressWarnings("unchecked") + public final T dispatchOptions(boolean dispatchOptions) { + this.dispatchOptions = dispatchOptions; + return (T) this; + } + + /** + * Build a {@link org.springframework.test.web.servlet.MockMvc} instance. + */ + @Override + public final MockMvc build() { + + WebApplicationContext wac = initWebAppContext(); + + ServletContext servletContext = wac.getServletContext(); + MockServletConfig mockServletConfig = new MockServletConfig(servletContext); + + Filter[] filterArray = this.filters.toArray(new Filter[this.filters.size()]); + + return super.createMockMvc(filterArray, mockServletConfig, wac, this.defaultRequestBuilder, + this.globalResultMatchers, this.globalResultHandlers, this.dispatchOptions); + } + + /** + * A method to obtain the WebApplicationContext to be passed to the DispatcherServlet. + * Invoked from {@link #build()} before the + * {@link org.springframework.test.web.servlet.MockMvc} instance is created. + */ + protected abstract WebApplicationContext initWebAppContext(); + +} diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/DefaultMockMvcBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/DefaultMockMvcBuilder.java index fd9c0b9d492..9968643ce14 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/DefaultMockMvcBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/DefaultMockMvcBuilder.java @@ -34,29 +34,17 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; /** - * An concrete implementation of {@link MockMvcBuilder} with methods for - * configuring filters, default request properties, and global expectations and - * result actions. + * An concrete implementation of {@link AbstractMockMvcBuilder} that simply + * provides the WebApplicationContext given to it as a constructor argument. * * @author Rossen Stoyanchev * @author Rob Winch * @since 3.2 */ -public class DefaultMockMvcBuilder> extends MockMvcBuilderSupport - implements MockMvcBuilder { +public class DefaultMockMvcBuilder extends AbstractMockMvcBuilder { private final WebApplicationContext webAppContext; - private List filters = new ArrayList(); - - private RequestBuilder defaultRequestBuilder; - - private final List globalResultMatchers = new ArrayList(); - - private final List globalResultHandlers = new ArrayList(); - - private Boolean dispatchOptions = Boolean.FALSE; - /** * Protected constructor. Not intended for direct instantiation. @@ -68,153 +56,10 @@ public class DefaultMockMvcBuilder> extends M this.webAppContext = webAppContext; } - /** - * Add filters mapped to any request (i.e. "/*"). For example: - * - *

-	 * mockMvcBuilder.addFilters(springSecurityFilterChain);
-	 * 
- * - *

is the equivalent of the following web.xml configuration: - * - *

-	 * <filter-mapping>
-	 *     <filter-name>springSecurityFilterChain</filter-name>
-	 *     <url-pattern>/*</url-pattern>
-	 * </filter-mapping>
-	 * 
- * - *

Filters will be invoked in the order in which they are provided. - * - * @param filters the filters to add - */ - @SuppressWarnings("unchecked") - public final T addFilters(Filter... filters) { - Assert.notNull(filters, "filters cannot be null"); - - for(Filter f : filters) { - Assert.notNull(f, "filters cannot contain null values"); - this.filters.add(f); - } - return (T) this; - } - - /** - * Add a filter mapped to a specific set of patterns. For example: - * - *

-	 * mockMvcBuilder.addFilters(myResourceFilter, "/resources/*");
-	 * 
- * - *

is the equivalent of: - * - *

-	 * <filter-mapping>
-	 *     <filter-name>myResourceFilter</filter-name>
-	 *     <url-pattern>/resources/*</url-pattern>
-	 * </filter-mapping>
-	 * 
- * - *

Filters will be invoked in the order in which they are provided. - * - * @param filter the filter to add - * @param urlPatterns URL patterns to map to; if empty, "/*" is used by default - */ - @SuppressWarnings("unchecked") - public final T addFilter(Filter filter, String... urlPatterns) { - - Assert.notNull(filter, "filter cannot be null"); - Assert.notNull(urlPatterns, "urlPatterns cannot be null"); - - if(urlPatterns.length > 0) { - filter = new PatternMappingFilterProxy(filter, urlPatterns); - } - - this.filters.add(filter); - return (T) this; - } - - /** - * Define default request properties that should be merged into all - * performed requests. In effect this provides a mechanism for defining - * common initialization for all requests such as the content type, request - * parameters, session attributes, and any other request property. - * - *

Properties specified at the time of performing a request override the - * default properties defined here. - * - * @param requestBuilder a RequestBuilder; see static factory methods in - * {@link org.springframework.test.web.servlet.request.MockMvcRequestBuilders} - * . - */ - @SuppressWarnings("unchecked") - public final T defaultRequest(RequestBuilder requestBuilder) { - this.defaultRequestBuilder = requestBuilder; - return (T) this; - } - - /** - * Define a global expectation that should always be applied to - * every response. For example, status code 200 (OK), content type - * {@code "application/json"}, etc. - * - * @param resultMatcher a ResultMatcher; see static factory methods in - * {@link org.springframework.test.web.servlet.result.MockMvcResultMatchers} - */ - @SuppressWarnings("unchecked") - public final T alwaysExpect(ResultMatcher resultMatcher) { - this.globalResultMatchers.add(resultMatcher); - return (T) this; - } - - /** - * Define a global action that should always be applied to every - * response. For example, writing detailed information about the performed - * request and resulting response to {@code System.out}. - * - * @param resultHandler a ResultHandler; see static factory methods in - * {@link org.springframework.test.web.servlet.result.MockMvcResultHandlers} - */ - @SuppressWarnings("unchecked") - public final T alwaysDo(ResultHandler resultHandler) { - this.globalResultHandlers.add(resultHandler); - return (T) this; - } - - /** - * Should the {@link DispatcherServlet} dispatch OPTIONS request to controllers. - * @param dispatchOptions - * @see DispatcherServlet#setDispatchOptionsRequest(boolean) - */ - @SuppressWarnings("unchecked") - public final T dispatchOptions(boolean dispatchOptions) { - this.dispatchOptions = dispatchOptions; - return (T) this; - } - /** - * Build a {@link MockMvc} instance. - */ @Override - public final MockMvc build() { - - initWebAppContext(this.webAppContext); - - ServletContext servletContext = this.webAppContext.getServletContext(); - MockServletConfig mockServletConfig = new MockServletConfig(servletContext); - - Filter[] filterArray = this.filters.toArray(new Filter[this.filters.size()]); - - return super.createMockMvc(filterArray, mockServletConfig, this.webAppContext, - this.defaultRequestBuilder, this.globalResultMatchers, this.globalResultHandlers,this.dispatchOptions); - } - - /** - * Invoked from {@link #build()} before the {@link MockMvc} instance is created. - * Allows sub-classes to further initialize the {@code WebApplicationContext} - * and the {@code javax.servlet.ServletContext} it contains. - */ - protected void initWebAppContext(WebApplicationContext webAppContext) { + protected WebApplicationContext initWebAppContext() { + return this.webAppContext; } } diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/MockMvcBuilders.java b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/MockMvcBuilders.java index 676c8bda9b8..2a9ee4633b9 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/MockMvcBuilders.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/MockMvcBuilders.java @@ -42,8 +42,8 @@ public class MockMvcBuilders { * application controllers in it. The context must have been configured with * a {@link ServletContext}. */ - public static > DefaultMockMvcBuilder webAppContextSetup(WebApplicationContext context) { - return new DefaultMockMvcBuilder(context); + public static DefaultMockMvcBuilder webAppContextSetup(WebApplicationContext context) { + return new DefaultMockMvcBuilder(context); } /** diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilder.java index 7794f48c59d..01425ef5cde 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilder.java @@ -82,7 +82,7 @@ import org.springframework.web.servlet.view.InternalResourceViewResolver; * @author Rossen Stoyanchev * @since 3.2 */ -public class StandaloneMockMvcBuilder extends DefaultMockMvcBuilder { +public class StandaloneMockMvcBuilder extends AbstractMockMvcBuilder { private final Object[] controllers; @@ -124,7 +124,6 @@ public class StandaloneMockMvcBuilder extends DefaultMockMvcBuilder initViewResolvers(WebApplicationContext wac) { diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/setup/DefaultMockMvcBuilderTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/setup/DefaultMockMvcBuilderTests.java index f7b07594ba8..d341bcec0be 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/setup/DefaultMockMvcBuilderTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/setup/DefaultMockMvcBuilderTests.java @@ -35,7 +35,7 @@ import org.springframework.web.filter.OncePerRequestFilter; */ public class DefaultMockMvcBuilderTests { - private DefaultMockMvcBuilder builder; + private StandaloneMockMvcBuilder builder; @Before public void setup() { diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilderTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilderTests.java index 840e4862cee..b2cf4f089a6 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilderTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilderTests.java @@ -21,6 +21,7 @@ import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.mock.web.test.MockServletContext; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.context.WebApplicationContext; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerExecutionChain; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; @@ -38,12 +39,11 @@ public class StandaloneMockMvcBuilderTests { @Test public void placeHoldersInRequestMapping() throws Exception { - StubWebApplicationContext cxt = new StubWebApplicationContext(new MockServletContext()); - StandaloneMockMvcBuilder builder = new StandaloneMockMvcBuilder(new PlaceholderController()); + TestStandaloneMockMvcBuilder builder = new TestStandaloneMockMvcBuilder(new PlaceholderController()); builder.addPlaceHolderValue("sys.login.ajax", "/foo"); - builder.initWebAppContext(cxt); + builder.build(); - RequestMappingHandlerMapping hm = cxt.getBean(RequestMappingHandlerMapping.class); + RequestMappingHandlerMapping hm = builder.wac.getBean(RequestMappingHandlerMapping.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo"); HandlerExecutionChain chain = hm.getHandler(request); @@ -60,4 +60,19 @@ public class StandaloneMockMvcBuilderTests { private void handleWithPlaceholders() { } } + + private static class TestStandaloneMockMvcBuilder extends StandaloneMockMvcBuilder { + + private WebApplicationContext wac; + + private TestStandaloneMockMvcBuilder(Object... controllers) { + super(controllers); + } + + @Override + protected WebApplicationContext initWebAppContext() { + this.wac = super.initWebAppContext(); + return this.wac; + } + } }