Integration Tests (What? Why? How?)

Integration testing allows us to test all of our application components at once to validate they function adequately. We’ll send HTTP requests to our controller, which at its time will forward the requests to our service implementation where any additional business logic will be handled. The requests will then reach our CRUD repository allowing us to fetch or manipulate whatever data is in our in-memory DB. Finally, the response will be returned to the client.

These tests are essentially used to imitate real requests our API will receive from clients. The tests will allow us to validate our expected client response payload and status codes for the respective client requests. These tests tend to take longer executing because they spin up the default embedded tomcat web server and deploying our app on it.

@SpringBootTest annotation enables a testing application context, allowing us to execute methods annotated with @Test. By default, SpringBootTest will not start the server. But if we define the 'webEnvironment' property as @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT OR WebEnvironment.DEFINED_PORT), spring will load a WebServerApplicationContext providing a real web environment. This property will start the embedded server listening on the defined or random port. The context uses the SpringBootContextLoader class and the @SpringBootConfiguration annotation by default. For your tests, you may specify which component classes to use for loading the Application Context and override specific configurations.

So how will we communicate with our API to mimic the HTTP requests? Glad you asked! To accomplish this, we’ll use both Spring’s TestRestTemplate and the REST-Assured framework.

TestRestTemplate vs. REST-Assured

It’s like comparing Coke vs. Pepsi- they’re pretty much the same thing. Just kidding Pepsi sucks! But in all seriousness, when it comes to RESTful based API integration testing and validation, both do the same thing. TestRestTemplate and REST-Assured offer convenient methods to create and execute your HTTP calls with custom headers, auth, content types, query parameters, payload content, cookies, etc. The main difference -aside from syntax- is that TestRestTemplate is part of Spring’s test framework which comes bundled with the ‘spring-boot-starter-test’ dependency. When using @SpringBootTest, TestRestTemplate’s bean is registered in the application context by default.

In this example, we’ll use both libraries to test and validate the same vehicle service API so that you can get an idea on how they are implemented. Let’s take a look at the rest-assured integration tests first:

Integration testing using Rest-Assured library example

Rest-assured integration tests

Integration testing using Spring’s TestRestTemplate example

TestRestTemplate integration tests

Note: One caveat of web app integration tests, is we can’t use @Transactional to roll back database transactions at the end of each test method. This is because the HTTP client and server run in separate threads. Having said this, be cautious of your assertions- you don’t want to assert an object exists right after a delete request ran in the previous test. Additionally, you could drop and create the DB schema after every single test method, but if it’s a sizable schema, it might result in long execution time.