RESTful Services test with RestTemplate

There's a good chapter on this in the documentation, I suggest you read through it to fully understand what you can do.

I like to use @IntegrationTest with a custom configuration since that starts up the entire server and lets you test the complete system. If you want to replace certain parts of the system with mocks you can do that by excluding certain configurations or beans and replacing them with your own.

Here's a small example. I've left out the MessageService interface because it's obvious from IndexController what it does, and it's default implementation - DefaultMessageService - because it's not relevant.

What it does is that it spins up the entire application minus the DefaultMessageService but with it's own MessageService instead. It then uses RestTemplate to issue real HTTP requests to the running application in the test case.

Application classes:

IntegrationTestDemo.java:

@SpringBootApplication
public class IntegrationTestDemo {

    public static void main(String[] args) {
        SpringApplication.run(IntegrationTestDemo.class, args);
    }

}

IndexController.java:

@RestController
public class IndexController {

    @Autowired
    MessageService messageService;

    @RequestMapping("/")
    String getMessage() {
        return messageService.getMessage();
    }
}

Test classes:

IntegrationTestDemoTest.java:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestConfig.class)
@WebIntegrationTest // This will start the server on a random port
public class IntegrationTestDemoTest {

    // This will hold the port number the server was started on
    @Value("${local.server.port}")
    int port;

    final RestTemplate template = new RestTemplate();

    @Test
    public void testGetMessage() {
        String message = template.getForObject("http://localhost:" + port + "/", String.class);

        Assert.assertEquals("This is a test message", message);
    }
}

TestConfig.java:

@SpringBootApplication
@ComponentScan(
    excludeFilters = {
        // Exclude the default message service
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = DefaultMessageService.class),
        // Exclude the default boot application or it's
        // @ComponentScan will pull in the default message service
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = IntegrationTestDemo.class)
    }
)
public class TestConfig {

    @Bean
    // Define our own test message service
    MessageService mockMessageService() {
        return new MessageService() {
            @Override
            public String getMessage() {
                return "This is a test message";
            }
        };
    }
}

If you were not looking for a end to end (integretion) test, the MockRestServiceServer might help you. I found it's very useful to de-couple my test cases from a real service.

Spring doc said:

Used for tests that involve direct or indirect use of the RestTemplate. Provides a way to set up expected requests that will be performed through the RestTemplate as well as mock responses to send back thus removing the need for an actual server.

Here is the official doc


One more tip is that, requestTo can not be imported automatically

server.expect(manyTimes(), requestTo("/hotels/42")) ....

It's a static method of org.springframework.test.web.client.match.MockRestRequestMatchers