Skip to content

Servlet mocks are not reinjected into test instance between TestNG test methods [SPR-11626] #16249

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task done
spring-projects-issues opened this issue Mar 29, 2014 · 1 comment
Assignees
Labels
in: test Issues in the test module status: backported An issue that has been backported to maintenance branches type: bug A general bug
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Mar 29, 2014

Sam Brannen opened SPR-11626 and commented

Status Quo

When executing TestNG-based integration tests that subclass AbstractTestNGSpringContextTests and are annotated with @WebAppConfiguration, if the ServletTestExecutionListener resets the request attributes stored in the RequestContextHolder after a test method, then any injected Servlet API mocks that are managed by the listener (e.g., MockHttpServletRequest, MockHttpServletResponse, and ServletWebRequest) will continue to hold values from the first such test method.

The net effect is that subsequent web tests will not have access to the current mocks.

See the referenced discussion on Stack Overflow for an example of a failing test case.


Analysis

The reason for this behavior is that ServletTestExecutionListener resets the request attributes after each test method, but DependencyInjectionTestExecutionListener does not re-inject dependencies before each test method (at least not by default). When a second test method is executed, an injected ServletRequest field will still reference the MockHttpServletRequest that was created for the previous test method; whereas, ServletTestExecutionListener creates a new instance of MockHttpServletRequest for each test method and sets it in the request attributes. Thus, the injected request and the one stored in the RequestContextHolder are only the same for the first test method that executes in TestNG.

Note: this bug only applies to TestNG tests; JUnit-based tests are not affected by this.


Temporary Work-Arounds

If you need a work-around before this fix is available, you have two options.

You can annotate the affected test methods with @DirtiesContext (or annotate your test class with @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)). This will allow your tests to pass as you expect. The use of @DirtiesContext will make Spring close your test ApplicationContext after each test method, and this will likely have a negative impact on the speed of your tests; however, as of Spring 3.2.8 and 4.0.3, this is the only non-custom solution.

The second option is a more efficient work-around. Just define this custom TestExecutionListener in your project:

public class AlwaysReinjectDependenciesTestExecutionListener extends AbstractTestExecutionListener {

  public void afterTestMethod(TestContext testContext) throws Exception {
    testContext.setAttribute(
      DependencyInjectionTestExecutionListener.REINJECT_DEPENDENCIES_ATTRIBUTE,
      Boolean.TRUE);
    }
}

And then annotate your test class like this:

@TestExecutionListeners(AlwaysReinjectDependenciesTestExecutionListener.class)

That should clear up any issues and keep your test suite running quickly.


Deliverables

  1. Ensure that Servlet mocks managed by the ServletTestExecutionListener are re-injected into test instances between TestNG methods, if the RequestContextHolder is reset.

Affects: 3.2 GA

Reference URL: http://stackoverflow.com/questions/22712325/multiple-tests-with-autowired-mockhttpservletrequest-not-working

Issue Links:

Backported to: 3.2.9

@spring-projects-issues
Copy link
Collaborator Author

Sam Brannen commented

This has been addressed as described in the comments for GitHub commits c386007 (4.1), cd9d7cf (4.0.4), and b31750f (3.2.9):

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.

@spring-projects-issues spring-projects-issues added type: bug A general bug in: test Issues in the test module status: backported An issue that has been backported to maintenance branches labels Jan 11, 2019
@spring-projects-issues spring-projects-issues added this to the 4.0.4 milestone Jan 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: test Issues in the test module status: backported An issue that has been backported to maintenance branches type: bug A general bug
Projects
None yet
Development

No branches or pull requests

2 participants