Does Spring @DirtiesContext reload Spring context?

2020-02-28 05:08发布

问题:

I have a test class that looks like

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/test-context.xml"})
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public abstract class TestClass {
  @Rule @Resource public JUnitRuleMockery jMockContext;

  public void test1() {
    //Expectations and test
  }
  public void test2() {
    //Expectations and test
  }
}

and in test-context.xml I define the JUnitRuleMockery plus several mock objects through a factory-method, like

<bean id="mockContextFactory" class="MockContextFactory" />

<bean id="jMockContext" factory-bean="mockContextFactory" factory-method="getContext" scope="prototype" />

<bean id="firstMock" factory-bean="mockContextFactory" factory-method="getFirstMock" />

<bean id="secondMock" factory-bean="mockContextFactory" factory-method="getSecondMock" />

MockContextFactory is

public class MockContextFactory
{
  private JUnitRuleMockery jUnitRuleMockery;

  public MockContextFactory() {
    jUnitRuleMockery = new JUnitRuleMockery();
    jUnitRuleMockery.setThreadingPolicy(new Synchroniser());
  }

  public JUnitRuleMockery getContext() {
    return jUnitRuleMockery;
  }

  public FirstMock getFirstMock() {
    return jUnitRuleMockery.mock(FirstMock.class);
  }
  //others getter
}

In TestClass I have several test methods and, due to the annotations @DirtiesContext, I am expecting the Spring context to be reloaded after each test execution (since each test sets expectations on mock objects, I have to reload Spring context every time). See @DirtiesContext from here. However, it appears that the Spring context is not reloaded: in fact, entering in debug mode at the beginning of test2 (supposedly test1 has been executed earlier) I can see jMockContext still holding expectations, execution list and errors (if any) from test1.
So, to end up with few questions, does @DirtiesContext really cause Spring context to be reloaded (as I understood from Spring Docs) or did I misunderstand the annotation? In the first case, what am I doing wrong? In the latter case, how can I force Spring context to be reloaded for every test?

EDIT, to delimit the problem: I had a code like the sample above running from few days, then today I created a new test in which I added an expectation which failed. Then, I saw all the other tests in the class failing for the same reason (while they where green until today). Debugging, I found out that jMockContext was never cleared, which means all tests were adding expectations to the same pool: of course, as long as no expectation failed, that was transparent and I did not notice it (test1 adds and passes few expectations, test2 takes a not-empty pool of expectations ALREADY passed and adds its own so there was no problem), but I do not like the previous situation and I would like to start each test with no previous set expectations at all.

回答1:

Here is my solution. I do not know if this is limited to Spring 3.2 or if it is a general misunderstanding, but simply using @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) is not enough to cause the entire Spring context to be reloaded for each test. I had to add also the DirtiesContextTestExecutionListener in @TestExecutionListeners.
So, in the end, what worked for me was just to change the annotation of my TestClass to

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/test-context.xml"})
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
@TestExecutionListeners({DirtiesContextTestExecutionListener.class})
public abstract class TestClass

Nothing else has to change.