7

I have following test class for my spring-integration application that passes sucessfully being launched alone

@SpringBootTest(classes = {BackupTestDefinition.class})
@ActiveProfiles({"test", "dev"})
@RunWith(SpringRunner.class)
public class BackupServiceTest {
    @Value(value = "${ne.endpoint}")
    private String ne;
    @Autowired
    private RestTemplate restTemplate;    
    private MockRestServiceServer mockServer;

    @Before
    public void setup() {
        mockServer = MockRestServiceServer.bindTo(restTemplate).build(new UnorderedRequestExpectationManager());
        mockServer.expect(ExpectedCount.manyTimes(), requestTo(UriComponentsBuilder.fromHttpUrl(ne).build().toUri())).andExpect(method(HttpMethod.POST)).andRespond(withSuccess());
    }

    @Test
    public void testNotificationProcessing() throws IOException, InterruptedException, InitializationException, ExecutionException {
        //some testing code
    }
}

But I have another test that has other settings (ExpectedCount.times(1)) for the same endpoint and has different TestDefinition. So there are couple of contexts cached in this test suite. And when I launch them together I receive following exception

at org.springframework.test.web.client.AbstractRequestExpectationManager.createUnexpectedRequestError(AbstractRequestExpectationManager.java:141)
at org.springframework.test.web.client.UnorderedRequestExpectationManager.validateRequestInternal(UnorderedRequestExpectationManager.java:49)
at org.springframework.test.web.client.AbstractRequestExpectationManager.validateRequest(AbstractRequestExpectationManager.java:76)
at org.springframework.test.web.client.MockRestServiceServer$MockClientHttpRequestFactory$1.executeInternal(MockRestServiceServer.java:289)
at org.springframework.mock.http.client.MockClientHttpRequest.execute(MockClientHttpRequest.java:94)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:659)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:620)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:538)
Caused by: java.lang.AssertionError: No further requests expected: HTTP POST

After hours of debugging I found out that settings were successfully applied, but looks like restTemplate was called from another context where number of attempts was exhausted. Can you please help me to find out how this issue can be resolved.

Oleg K.
  • 137
  • 1
  • 1
  • 6

1 Answers1

3

This issue can be resolved using @DirtiesContext on the test class, alongside with the @RunWith:

 * Test annotation which indicates that the
 * {@link org.springframework.context.ApplicationContext ApplicationContext}
 * associated with a test is <em>dirty</em> and should therefore be closed
 * and removed from the context cache.
 *
 * <p>Use this annotation if a test has modified the context &mdash; for
 * example, by modifying the state of a singleton bean, modifying the state
 * of an embedded database, etc. Subsequent tests that request the same
 * context will be supplied a new context.
 *
 * <p>{@code @DirtiesContext} may be used as a class-level and method-level
 * annotation within the same class or class hierarchy. In such scenarios, the
 * {@code ApplicationContext} will be marked as <em>dirty</em> before or
 * after any such annotated method as well as before or after the current test
 * class, depending on the configured {@link #methodMode} and {@link #classMode}.
 *

And here are Docs on the matter: https://docs.spring.io/spring/docs/5.0.6.RELEASE/spring-framework-reference/testing.html#dirtiescontext

Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • 2
    Is this the only possible solution for this problem? As my test suite contains a lot of test classes and changing them is not desired. – Oleg K. May 08 '18 at 20:35
  • Well, if you don't cache and don't share context between tests, you are more stable and you don't need *hours of debugging* to figure out what is the problem. That's just a matter of adding one annotation. On the other hand this is `@Inherited`, so you can specify it on the super class for those tests. That is the way we went in our projects after some experience with a ton of unexpected failures, especially when we deal with shared resources (DB, JMS, files etc.) and some scheduled tasks. – Artem Bilan May 08 '18 at 20:41
  • Thank you so much for this answer, I had tests with and without MockRestServiceServer in my suite, so the ones without got bothered by the non-existent mock responses and this solved it. – eyesfree Aug 30 '23 at 09:22