Search code examples
spring-bootspring-testmockrestserviceserver

Using MockRestServiceServer only in subset of tests


I want to test outgoing HTTP calls from my service using MockRestServiceServer. I got it working using following code:

@SpringBootTest
class CommentFetcherTest {

@Autowired
RestTemplate restTemplate;

@Autowired
CommentFetcher commentFetcher;


@Test
public void shouldCallExternalService(){

    MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate);

    mockServer.expect(ExpectedCount.once(), requestTo("/test/endpoint")).andExpect(method(HttpMethod.GET));

    //when
    commentFetcher.fetchData();

    mockServer.verify();

}
}

However the problem I run into is that RestTemplate is a bean shared between all tests from suite what makes impossible to further run integration tests which should be calling external services. This results in :

java.lang.AssertionError: No further requests expected

How is it possible to use MockRestServiceServer only for subset of tests? I can't get rid of Dependency Injection through @Autowired and construct my service in tests such as

RestTemplate restTemplate = new RestTemplate();
CommentFetcher commentFetcher = new CommentFetcher(restTemplate);

As this would not read properties from application.properties necessary to proper functioning of my service.


Solution

  • Spring Boot provides a convenient way to test your client classes that make use of Spring's RestTemplate using @RestClientTest.

    With this annotation, you get a Spring Test Context that only contains relevant beans and not your whole application context (which is what you currently get with @SpringBootTest).

    The MockRestServiceServer is also part of this context and the RestTemplate is configured to target it.

    A basic test setup can look like the following:

    @RestClientTest(CommentFetcher.class)
    class UserClientTest {
     
      @Autowired
      private CommentFetcher userClient;
     
      @Autowired
      private MockRestServiceServer mockRestServiceServer;
     
      // ...
     
     
    }
    

    What's left is to stub the HTTP method call and then invoke the method on your class under test (commentFetcher.fetchData(); in your case).

    Refer to this article if you want to understand more about how @RestClientTest can be used to test your RestTemplate usage.