Skip to content

Commit b31750f

Browse files
committed
Reinject Servlet mocks between TestNG test methods
Prior to this commit, if multiple test methods were executed in a subclass of AbstractTestNGSpringContextTests annotated with @WebAppConfiguration, then injected Servlet API mocks would only reference the mocks created for the first test method. Subsequent test methods could therefore never reference the current mocks, and there was a discrepancy between the state of the injected mocks and the mock set in the RequestContextHolder. This commit addresses this issue by ensuring that dependencies (including updated mocks) are injected into the test instance before the next test method if the ServletTestExecutionListener resets the request attributes in RequestContextHolder. Issue: SPR-11626 (cherry picked from commit c386007)
1 parent a4a2e80 commit b31750f

File tree

3 files changed

+167
-5
lines changed

3 files changed

+167
-5
lines changed

spring-test/src/main/java/org/springframework/test/context/web/ServletTestExecutionListener.java

+11-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
3131
import org.springframework.test.context.TestContext;
3232
import org.springframework.test.context.TestExecutionListener;
3333
import org.springframework.test.context.support.AbstractTestExecutionListener;
34+
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
3435
import org.springframework.util.Assert;
3536
import org.springframework.web.context.WebApplicationContext;
3637
import org.springframework.web.context.request.RequestContextHolder;
@@ -115,11 +116,14 @@ public void beforeTestMethod(TestContext testContext) throws Exception {
115116
}
116117

117118
/**
118-
* Cleans up thread-local state after each test method by {@linkplain
119+
* If the {@link #RESET_REQUEST_CONTEXT_HOLDER_ATTRIBUTE} in the supplied
120+
* {@code TestContext} has a value of {@link Boolean#TRUE}, this method will
121+
* (1) clean up thread-local state after each test method by {@linkplain
119122
* RequestContextHolder#resetRequestAttributes() resetting} Spring Web's
120-
* {@code RequestContextHolder}, but only if the {@link
121-
* #RESET_REQUEST_CONTEXT_HOLDER_ATTRIBUTE} in the supplied {@code TestContext}
122-
* has a value of {@link Boolean#TRUE}.
123+
* {@code RequestContextHolder} and (2) ensure that new mocks are injected
124+
* into the test instance for subsequent tests by setting the
125+
* {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE}
126+
* in the test context to {@code true}.
123127
*
124128
* <p>The {@link #RESET_REQUEST_CONTEXT_HOLDER_ATTRIBUTE} and
125129
* {@link #POPULATED_REQUEST_CONTEXT_HOLDER_ATTRIBUTE} will be subsequently
@@ -133,6 +137,8 @@ public void afterTestMethod(TestContext testContext) throws Exception {
133137
logger.debug(String.format("Resetting RequestContextHolder for test context %s.", testContext));
134138
}
135139
RequestContextHolder.resetRequestAttributes();
140+
testContext.setAttribute(DependencyInjectionTestExecutionListener.REINJECT_DEPENDENCIES_ATTRIBUTE,
141+
Boolean.TRUE);
136142
}
137143
testContext.removeAttribute(POPULATED_REQUEST_CONTEXT_HOLDER_ATTRIBUTE);
138144
testContext.removeAttribute(RESET_REQUEST_CONTEXT_HOLDER_ATTRIBUTE);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2002-2014 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.test.context.testng.web;
18+
19+
import org.springframework.beans.factory.annotation.Autowired;
20+
import org.springframework.context.annotation.Configuration;
21+
import org.springframework.mock.web.MockHttpServletRequest;
22+
import org.springframework.test.context.ContextConfiguration;
23+
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
24+
import org.springframework.test.context.web.ServletTestExecutionListener;
25+
import org.springframework.test.context.web.WebAppConfiguration;
26+
import org.springframework.web.context.request.RequestContextHolder;
27+
import org.springframework.web.context.request.ServletRequestAttributes;
28+
import org.testng.annotations.Test;
29+
30+
import static org.junit.Assert.*;
31+
32+
/**
33+
* TestNG-based integration tests for {@link ServletTestExecutionListener}.
34+
*
35+
* @author Sam Brannen
36+
* @since 3.2.9
37+
* @see org.springframework.test.context.web.ServletTestExecutionListenerJUnitIntegrationTests
38+
*/
39+
@ContextConfiguration
40+
@WebAppConfiguration
41+
public class ServletTestExecutionListenerTestNGIntegrationTests extends AbstractTestNGSpringContextTests {
42+
43+
@Configuration
44+
static class Config {
45+
/* no beans required for this test */
46+
}
47+
48+
49+
@Autowired
50+
private MockHttpServletRequest servletRequest;
51+
52+
53+
/**
54+
* Verifies bug fix for <a href="https://jira.spring.io/browse/SPR-11626">SPR-11626</a>.
55+
*
56+
* @see #ensureMocksAreReinjectedBetweenTests_2
57+
*/
58+
@Test
59+
public void ensureMocksAreReinjectedBetweenTests_1() {
60+
assertInjectedServletRequestEqualsRequestInRequestContextHolder();
61+
}
62+
63+
/**
64+
* Verifies bug fix for <a href="https://jira.spring.io/browse/SPR-11626">SPR-11626</a>.
65+
*
66+
* @see #ensureMocksAreReinjectedBetweenTests_1
67+
*/
68+
@Test
69+
public void ensureMocksAreReinjectedBetweenTests_2() {
70+
assertInjectedServletRequestEqualsRequestInRequestContextHolder();
71+
}
72+
73+
private void assertInjectedServletRequestEqualsRequestInRequestContextHolder() {
74+
assertEquals("Injected ServletRequest must be stored in the RequestContextHolder", servletRequest,
75+
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest());
76+
}
77+
78+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2002-2014 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.test.context.web;
18+
19+
import org.junit.Test;
20+
import org.junit.runner.RunWith;
21+
import org.springframework.beans.factory.annotation.Autowired;
22+
import org.springframework.context.annotation.Configuration;
23+
import org.springframework.mock.web.MockHttpServletRequest;
24+
import org.springframework.test.context.ContextConfiguration;
25+
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
26+
import org.springframework.web.context.request.RequestContextHolder;
27+
import org.springframework.web.context.request.ServletRequestAttributes;
28+
29+
import static org.junit.Assert.*;
30+
31+
/**
32+
* JUnit-based integration tests for {@link ServletTestExecutionListener}.
33+
*
34+
* @author Sam Brannen
35+
* @since 3.2.9
36+
* @see org.springframework.test.context.testng.web.ServletTestExecutionListenerTestNGIntegrationTests
37+
*/
38+
@RunWith(SpringJUnit4ClassRunner.class)
39+
@ContextConfiguration
40+
@WebAppConfiguration
41+
public class ServletTestExecutionListenerJUnitIntegrationTests {
42+
43+
@Configuration
44+
static class Config {
45+
/* no beans required for this test */
46+
}
47+
48+
49+
@Autowired
50+
private MockHttpServletRequest servletRequest;
51+
52+
53+
/**
54+
* Verifies bug fix for <a href="https://jira.spring.io/browse/SPR-11626">SPR-11626</a>.
55+
*
56+
* @see #ensureMocksAreReinjectedBetweenTests_2
57+
*/
58+
@Test
59+
public void ensureMocksAreReinjectedBetweenTests_1() {
60+
assertInjectedServletRequestEqualsRequestInRequestContextHolder();
61+
}
62+
63+
/**
64+
* Verifies bug fix for <a href="https://jira.spring.io/browse/SPR-11626">SPR-11626</a>.
65+
*
66+
* @see #ensureMocksAreReinjectedBetweenTests_1
67+
*/
68+
@Test
69+
public void ensureMocksAreReinjectedBetweenTests_2() {
70+
assertInjectedServletRequestEqualsRequestInRequestContextHolder();
71+
}
72+
73+
private void assertInjectedServletRequestEqualsRequestInRequestContextHolder() {
74+
assertEquals("Injected ServletRequest must be stored in the RequestContextHolder", servletRequest,
75+
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest());
76+
}
77+
78+
}

0 commit comments

Comments
 (0)