Browse Source

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 c38600762dd17c5b4f1dabeb42c2dff77b5a66d1)
pull/531/head
Sam Brannen 12 years ago
parent
commit
cd9d7cfe4f
  1. 16
      spring-test/src/main/java/org/springframework/test/context/web/ServletTestExecutionListener.java
  2. 78
      spring-test/src/test/java/org/springframework/test/context/testng/web/ServletTestExecutionListenerTestNGIntegrationTests.java
  3. 78
      spring-test/src/test/java/org/springframework/test/context/web/ServletTestExecutionListenerJUnitIntegrationTests.java

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@ -31,6 +31,7 @@ import org.springframework.mock.web.MockServletContext; @@ -31,6 +31,7 @@ import org.springframework.mock.web.MockServletContext;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.TestExecutionListener;
import org.springframework.test.context.support.AbstractTestExecutionListener;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.util.Assert;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
@ -115,11 +116,14 @@ public class ServletTestExecutionListener extends AbstractTestExecutionListener @@ -115,11 +116,14 @@ public class ServletTestExecutionListener extends AbstractTestExecutionListener
}
/**
* Cleans up thread-local state after each test method by {@linkplain
* If the {@link #RESET_REQUEST_CONTEXT_HOLDER_ATTRIBUTE} in the supplied
* {@code TestContext} has a value of {@link Boolean#TRUE}, this method will
* (1) clean up thread-local state after each test method by {@linkplain
* RequestContextHolder#resetRequestAttributes() resetting} Spring Web's
* {@code RequestContextHolder}, but only if the {@link
* #RESET_REQUEST_CONTEXT_HOLDER_ATTRIBUTE} in the supplied {@code TestContext}
* has a value of {@link Boolean#TRUE}.
* {@code RequestContextHolder} and (2) ensure that new mocks are injected
* into the test instance for subsequent tests by setting the
* {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE}
* in the test context to {@code true}.
*
* <p>The {@link #RESET_REQUEST_CONTEXT_HOLDER_ATTRIBUTE} and
* {@link #POPULATED_REQUEST_CONTEXT_HOLDER_ATTRIBUTE} will be subsequently
@ -134,6 +138,8 @@ public class ServletTestExecutionListener extends AbstractTestExecutionListener @@ -134,6 +138,8 @@ public class ServletTestExecutionListener extends AbstractTestExecutionListener
logger.debug(String.format("Resetting RequestContextHolder for test context %s.", testContext));
}
RequestContextHolder.resetRequestAttributes();
testContext.setAttribute(DependencyInjectionTestExecutionListener.REINJECT_DEPENDENCIES_ATTRIBUTE,
Boolean.TRUE);
}
testContext.removeAttribute(POPULATED_REQUEST_CONTEXT_HOLDER_ATTRIBUTE);
testContext.removeAttribute(RESET_REQUEST_CONTEXT_HOLDER_ATTRIBUTE);

78
spring-test/src/test/java/org/springframework/test/context/testng/web/ServletTestExecutionListenerTestNGIntegrationTests.java

@ -0,0 +1,78 @@ @@ -0,0 +1,78 @@
/*
* Copyright 2002-2014 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.context.testng.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.springframework.test.context.web.ServletTestExecutionListener;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.testng.annotations.Test;
import static org.junit.Assert.*;
/**
* TestNG-based integration tests for {@link ServletTestExecutionListener}.
*
* @author Sam Brannen
* @since 3.2.9
* @see org.springframework.test.context.web.ServletTestExecutionListenerJUnitIntegrationTests
*/
@ContextConfiguration
@WebAppConfiguration
public class ServletTestExecutionListenerTestNGIntegrationTests extends AbstractTestNGSpringContextTests {
@Configuration
static class Config {
/* no beans required for this test */
}
@Autowired
private MockHttpServletRequest servletRequest;
/**
* Verifies bug fix for <a href="https://jira.spring.io/browse/SPR-11626">SPR-11626</a>.
*
* @see #ensureMocksAreReinjectedBetweenTests_2
*/
@Test
public void ensureMocksAreReinjectedBetweenTests_1() {
assertInjectedServletRequestEqualsRequestInRequestContextHolder();
}
/**
* Verifies bug fix for <a href="https://jira.spring.io/browse/SPR-11626">SPR-11626</a>.
*
* @see #ensureMocksAreReinjectedBetweenTests_1
*/
@Test
public void ensureMocksAreReinjectedBetweenTests_2() {
assertInjectedServletRequestEqualsRequestInRequestContextHolder();
}
private void assertInjectedServletRequestEqualsRequestInRequestContextHolder() {
assertEquals("Injected ServletRequest must be stored in the RequestContextHolder", servletRequest,
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest());
}
}

78
spring-test/src/test/java/org/springframework/test/context/web/ServletTestExecutionListenerJUnitIntegrationTests.java

@ -0,0 +1,78 @@ @@ -0,0 +1,78 @@
/*
* Copyright 2002-2014 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.context.web;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import static org.junit.Assert.*;
/**
* JUnit-based integration tests for {@link ServletTestExecutionListener}.
*
* @author Sam Brannen
* @since 3.2.9
* @see org.springframework.test.context.testng.web.ServletTestExecutionListenerTestNGIntegrationTests
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@WebAppConfiguration
public class ServletTestExecutionListenerJUnitIntegrationTests {
@Configuration
static class Config {
/* no beans required for this test */
}
@Autowired
private MockHttpServletRequest servletRequest;
/**
* Verifies bug fix for <a href="https://jira.spring.io/browse/SPR-11626">SPR-11626</a>.
*
* @see #ensureMocksAreReinjectedBetweenTests_2
*/
@Test
public void ensureMocksAreReinjectedBetweenTests_1() {
assertInjectedServletRequestEqualsRequestInRequestContextHolder();
}
/**
* Verifies bug fix for <a href="https://jira.spring.io/browse/SPR-11626">SPR-11626</a>.
*
* @see #ensureMocksAreReinjectedBetweenTests_1
*/
@Test
public void ensureMocksAreReinjectedBetweenTests_2() {
assertInjectedServletRequestEqualsRequestInRequestContextHolder();
}
private void assertInjectedServletRequestEqualsRequestInRequestContextHolder() {
assertEquals("Injected ServletRequest must be stored in the RequestContextHolder", servletRequest,
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest());
}
}
Loading…
Cancel
Save