Skip to content

Commit a73280c

Browse files
committed
Support loading WebApplicationContexts in the TCF
Prior to this commit, the Spring TestContext Framework only supported loading an ApplicationContext in integration tests from either XML or Java Properties files (since Spring 2.5), and Spring 3.1 introduced support for loading an ApplicationContext in integration tests from annotated classes (e.g., @configuration classes). All of the ContextLoader implementations used to provide this support load a GenericApplicationContext. However, a GenericApplicationContext is not suitable for testing a web application since a web application relies on an implementation of WebApplicationContext (WAC). This commit makes it possible to integration test Spring-powered web applications by adding the following functionality to the Spring TestContext Framework. - Introduced AbstractGenericWebContextLoader and two concrete subclasses: - XmlWebContextLoader - AnnotationConfigWebContextLoader - Pulled up prepareContext(context, mergedConfig) from AbstractGenericContextLoader into AbstractContextLoader to allow it to be shared across web and non-web context loaders. - Introduced AnnotationConfigContextLoaderUtils and refactored AnnotationConfigContextLoader accordingly. These utils are also used by AnnotationConfigWebContextLoader. - Introduced a new @WebAppConfiguration annotation to denote that the ApplicationContext loaded for a test should be a WAC and to configure the base resource path for the root directory of a web application. - Introduced WebMergedContextConfiguration which extends MergedContextConfiguration with support for a baseResourcePath for the root directory of a web application. - ContextLoaderUtils.buildMergedContextConfiguration() now builds a WebMergedContextConfiguration instead of a standard MergedContextConfiguration if @WebAppConfiguration is present on the test class. - Introduced a configureWebResources() method in AbstractGenericWebContextLoader that is responsible for creating a MockServletContext with a proper ResourceLoader for the resourceBasePath configured in the WebMergedContextConfiguration. The resulting mock ServletContext is set in the WAC, and the WAC is stored as the Root WAC in the ServletContext. - Introduced a WebTestExecutionListener that sets up default thread local state via RequestContextHolder before each test method by using the MockServletContext already present in the WAC and by creating a MockHttpServletRequest, MockHttpServletResponse, and ServletWebRequest that is set in the RequestContextHolder. WTEL also ensures that the MockHttpServletResponse and ServletWebRequest can be injected into the test instance (e.g., via @Autowired) and cleans up thread locals after each test method. - WebTestExecutionListener is configured as a default TestExecutionListener before DependencyInjectionTestExecutionListener - Extracted AbstractDelegatingSmartContextLoader from DelegatingSmartContextLoader and introduced a new WebDelegatingSmartContextLoader. - ContextLoaderUtils now selects the default delegating ContextLoader class name based on the presence of @WebAppConfiguration on the test class. - Tests in the spring-test-mvc module no longer use a custom ContextLoader to load a WebApplicationContext. Instead, they now rely on new core functionality provided in this commit. Issue: SPR-5243
1 parent 3552173 commit a73280c

29 files changed

+1474
-601
lines changed

spring-test-mvc/src/test/java/org/springframework/test/web/mock/servlet/samples/context/GenericWebContextLoader.java

Lines changed: 0 additions & 94 deletions
This file was deleted.

spring-test-mvc/src/test/java/org/springframework/test/web/mock/servlet/samples/context/JavaTestContextTests.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,48 +16,47 @@
1616

1717
package org.springframework.test.web.mock.servlet.samples.context;
1818

19-
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.get;
20-
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.forwardedUrl;
21-
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.status;
19+
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.*;
20+
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.*;
2221

2322
import org.junit.Before;
2423
import org.junit.Test;
2524
import org.junit.runner.RunWith;
2625
import org.springframework.beans.factory.annotation.Autowired;
2726
import org.springframework.test.context.ContextConfiguration;
2827
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
28+
import org.springframework.test.context.web.WebAppConfiguration;
2929
import org.springframework.test.web.mock.servlet.MockMvc;
3030
import org.springframework.test.web.mock.servlet.setup.MockMvcBuilders;
31-
import org.springframework.web.context.ContextLoader;
3231
import org.springframework.web.context.WebApplicationContext;
3332

3433
/**
3534
* Tests with Java configuration.
3635
*
37-
* The TestContext framework doesn't support WebApplicationContext yet:
38-
* https://jira.springsource.org/browse/SPR-5243
39-
*
40-
* A custom {@link ContextLoader} is used to load the WebApplicationContext.
36+
* @author Rossen Stoyanchev
37+
* @author Sam Brannen
4138
*/
4239
@RunWith(SpringJUnit4ClassRunner.class)
43-
@ContextConfiguration(loader=WebContextLoader.class, classes={WebConfig.class})
40+
@WebAppConfiguration("src/test/resources/META-INF/web-resources")
41+
@ContextConfiguration(classes = WebConfig.class)
4442
public class JavaTestContextTests {
4543

4644
@Autowired
4745
private WebApplicationContext wac;
4846

4947
private MockMvc mockMvc;
5048

49+
5150
@Before
5251
public void setup() {
5352
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
5453
}
5554

5655
@Test
5756
public void tilesDefinitions() throws Exception {
58-
this.mockMvc.perform(get("/"))
59-
.andExpect(status().isOk())
60-
.andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
57+
this.mockMvc.perform(get("/"))//
58+
.andExpect(status().isOk())//
59+
.andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
6160
}
6261

6362
}

spring-test-mvc/src/test/java/org/springframework/test/web/mock/servlet/samples/context/SpringSecurityTests.java

Lines changed: 47 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
1111
* specific language governing permissions and limitations under the License.
1212
*/
13+
1314
package org.springframework.test.web.mock.servlet.samples.context;
1415

1516
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.get;
@@ -34,6 +35,7 @@
3435
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
3536
import org.springframework.test.context.ContextConfiguration;
3637
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
38+
import org.springframework.test.context.web.WebAppConfiguration;
3739
import org.springframework.test.web.mock.servlet.MockMvc;
3840
import org.springframework.test.web.mock.servlet.MvcResult;
3941
import org.springframework.test.web.mock.servlet.ResultMatcher;
@@ -44,32 +46,25 @@
4446
/**
4547
* Basic example that includes Spring Security configuration.
4648
*
47-
* <p>Note that currently there are no {@link ResultMatcher}' built specifically
48-
* for asserting the Spring Security context. However, it's quite easy to put
49-
* them together as shown below and Spring Security extensions will become
50-
* available in the near future.
49+
* <p>Note that currently there are no {@linkplain ResultMatcher ResultMatchers}
50+
* built specifically for asserting the Spring Security context. However, it's
51+
* quite easy to put them together as shown below, and Spring Security extensions
52+
* will become available in the near future.
5153
*
5254
* <p>This also demonstrates a custom {@link RequestPostProcessor} which authenticates
5355
* a user to a particular {@link HttpServletRequest}.
5456
*
55-
* <p>Also see the Javadoc of {@link GenericWebContextLoader}, a class that
56-
* provides temporary support for loading WebApplicationContext by extending
57-
* the TestContext framework.
58-
*
5957
* @author Rob Winch
6058
* @author Rossen Stoyanchev
59+
* @author Sam Brannen
6160
* @see SecurityRequestPostProcessors
6261
*/
6362
@RunWith(SpringJUnit4ClassRunner.class)
64-
@ContextConfiguration(
65-
loader=WebContextLoader.class,
66-
value={
67-
"classpath:org/springframework/test/web/mock/servlet/samples/context/security.xml",
68-
"classpath:org/springframework/test/web/mock/servlet/samples/servlet-context.xml"
69-
})
63+
@WebAppConfiguration("src/test/resources/META-INF/web-resources")
64+
@ContextConfiguration({ "security.xml", "../servlet-context.xml" })
7065
public class SpringSecurityTests {
7166

72-
private static String SEC_CONTEXT_ATTR = HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY;
67+
private static final String SEC_CONTEXT_ATTR = HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY;
7368

7469
@Autowired
7570
private FilterChainProxy springSecurityFilterChain;
@@ -79,57 +74,67 @@ public class SpringSecurityTests {
7974

8075
private MockMvc mockMvc;
8176

77+
8278
@Before
8379
public void setup() {
84-
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
85-
.addFilters(this.springSecurityFilterChain).build();
80+
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)//
81+
.addFilters(this.springSecurityFilterChain)//
82+
.build();
8683
}
8784

8885
@Test
8986
public void requiresAuthentication() throws Exception {
90-
mockMvc.perform(get("/user"))
91-
.andExpect(redirectedUrl("http://localhost/spring_security_login"));
87+
mockMvc.perform(get("/user")).//
88+
andExpect(redirectedUrl("http://localhost/spring_security_login"));
9289
}
9390

9491
@Test
9592
public void accessGranted() throws Exception {
96-
this.mockMvc.perform(get("/").with(userDeatilsService("user")))
97-
.andExpect(status().isOk())
98-
.andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
93+
this.mockMvc.perform(get("/").//
94+
with(userDeatilsService("user"))).//
95+
andExpect(status().isOk()).//
96+
andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
9997
}
10098

10199
@Test
102100
public void accessDenied() throws Exception {
103-
this.mockMvc.perform(get("/").with(user("user").roles("DENIED")))
104-
.andExpect(status().isForbidden());
101+
this.mockMvc.perform(get("/")//
102+
.with(user("user").roles("DENIED")))//
103+
.andExpect(status().isForbidden());
105104
}
106105

107106
@Test
108107
public void userAuthenticates() throws Exception {
109108
final String username = "user";
110-
mockMvc.perform(post("/j_spring_security_check").param("j_username", username).param("j_password", "password"))
111-
.andExpect(redirectedUrl("/"))
112-
.andExpect(new ResultMatcher() {
113-
public void match(MvcResult mvcResult) throws Exception {
114-
HttpSession session = mvcResult.getRequest().getSession();
115-
SecurityContext securityContext = (SecurityContext) session.getAttribute(SEC_CONTEXT_ATTR);
116-
Assert.assertEquals(securityContext.getAuthentication().getName(), username);
117-
}
118-
});
109+
mockMvc.perform(post("/j_spring_security_check").//
110+
param("j_username", username).//
111+
param("j_password", "password")).//
112+
andExpect(redirectedUrl("/")).//
113+
andExpect(new ResultMatcher() {
114+
115+
public void match(MvcResult mvcResult) throws Exception {
116+
HttpSession session = mvcResult.getRequest().getSession();
117+
SecurityContext securityContext = (SecurityContext) session.getAttribute(SEC_CONTEXT_ATTR);
118+
Assert.assertEquals(securityContext.getAuthentication().getName(), username);
119+
}
120+
});
119121
}
120122

121123
@Test
122124
public void userAuthenticateFails() throws Exception {
123125
final String username = "user";
124-
mockMvc.perform(post("/j_spring_security_check").param("j_username", username).param("j_password", "invalid"))
125-
.andExpect(redirectedUrl("/spring_security_login?login_error"))
126-
.andExpect(new ResultMatcher() {
127-
public void match(MvcResult mvcResult) throws Exception {
128-
HttpSession session = mvcResult.getRequest().getSession();
129-
SecurityContext securityContext = (SecurityContext) session.getAttribute(SEC_CONTEXT_ATTR);
130-
Assert.assertNull(securityContext);
131-
}
132-
});
126+
mockMvc.perform(post("/j_spring_security_check").//
127+
param("j_username", username).//
128+
param("j_password", "invalid")).//
129+
andExpect(redirectedUrl("/spring_security_login?login_error")).//
130+
andExpect(new ResultMatcher() {
131+
132+
public void match(MvcResult mvcResult) throws Exception {
133+
HttpSession session = mvcResult.getRequest().getSession();
134+
SecurityContext securityContext = (SecurityContext) session.getAttribute(SEC_CONTEXT_ATTR);
135+
Assert.assertNull(securityContext);
136+
}
137+
});
133138
}
134139

135140
}

spring-test-mvc/src/test/java/org/springframework/test/web/mock/servlet/samples/context/XmlTestContextTests.java

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,51 +16,47 @@
1616

1717
package org.springframework.test.web.mock.servlet.samples.context;
1818

19-
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.get;
20-
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.forwardedUrl;
21-
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.status;
19+
import static org.springframework.test.web.mock.servlet.request.MockMvcRequestBuilders.*;
20+
import static org.springframework.test.web.mock.servlet.result.MockMvcResultMatchers.*;
2221

2322
import org.junit.Before;
2423
import org.junit.Test;
2524
import org.junit.runner.RunWith;
2625
import org.springframework.beans.factory.annotation.Autowired;
2726
import org.springframework.test.context.ContextConfiguration;
2827
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
28+
import org.springframework.test.context.web.WebAppConfiguration;
2929
import org.springframework.test.web.mock.servlet.MockMvc;
3030
import org.springframework.test.web.mock.servlet.setup.MockMvcBuilders;
31-
import org.springframework.web.context.ContextLoader;
3231
import org.springframework.web.context.WebApplicationContext;
3332

3433
/**
3534
* Tests with XML configuration.
3635
*
37-
* The TestContext framework doesn't support WebApplicationContext yet:
38-
* https://jira.springsource.org/browse/SPR-5243
39-
*
40-
* A custom {@link ContextLoader} is used to load the WebApplicationContext.
36+
* @author Rossen Stoyanchev
37+
* @author Sam Brannen
4138
*/
4239
@RunWith(SpringJUnit4ClassRunner.class)
43-
@ContextConfiguration(
44-
loader=WebContextLoader.class,
45-
locations={"/org/springframework/test/web/mock/servlet/samples/servlet-context.xml"})
40+
@WebAppConfiguration("src/test/resources/META-INF/web-resources")
41+
@ContextConfiguration("../servlet-context.xml")
4642
public class XmlTestContextTests {
4743

4844
@Autowired
4945
private WebApplicationContext wac;
5046

5147
private MockMvc mockMvc;
5248

49+
5350
@Before
5451
public void setup() {
5552
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
5653
}
5754

5855
@Test
5956
public void tilesDefinitions() throws Exception {
60-
this.mockMvc.perform(get("/"))
61-
.andExpect(status().isOk())
62-
.andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
57+
this.mockMvc.perform(get("/"))//
58+
.andExpect(status().isOk())//
59+
.andExpect(forwardedUrl("/WEB-INF/layouts/standardLayout.jsp"));
6360
}
6461

6562
}
66-

spring-test/.springBeans

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<configs>
1010
<config>src/test/java/org/springframework/test/context/junit4/profile/xml/DefaultProfileXmlConfigTests-context.xml</config>
1111
<config>src/test/java/org/springframework/test/context/junit4/aci/xml/MultipleInitializersXmlConfigTests-context.xml</config>
12+
<config>src/test/resources/org/springframework/test/context/web/BasicXmlWacTests-config.xml</config>
1213
</configs>
1314
<configSets>
1415
</configSets>

0 commit comments

Comments
 (0)