From here on, I assume your application has a good unit test coverage. So, you can start writing an integration test using the @SpringBootTest
annotation.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class DemoApplicationTests {
@Autowired
lateinit var testRestTemplate: TestRestTemplate
@Test
fun `should call hello`() {
val response = testRestTemplate.getForEntity("/hello", String::class.java)
assertThat(response.statusCode.is2xxSuccessful)
assertThat(response.body).isNotBlank()
}
}
You also need to use the Spring Boot Docker Compose integration. Add this to your pom.xml
file:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-docker-compose</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
To make it work, you have to create a Docker Compose file in the root folder of your application, and Spring Boot will start it when your application starts and stop it when your application stops.
services:
postgres:
image: 'postgres:latest'
environment:
- 'POSTGRES_DB=mydatabase'
- 'POSTGRES_PASSWORD=secret'
- 'POSTGRES_USER=myuser'
ports:
- '5432'
redis:
image: 'redis:latest'
ports:
- '6379'
Always use the same version as you have in the production environment. This way, your tests will run in an environment similar to production. Don't use latest
, as you can see in the example.
If you run the test, your application will fail to start. There is only one configuration needed to glue your tests with Docker Compose. Add this to the application.yml
file in the test resources folder:
spring:
docker:
compose:
skip:
in-tests: false
Voila! Your tests are running, and Spring Boot is handling all the plumbing. We did not configure connection strings at any moment because Spring manages everything.
Another benefit is that you can also run it in your pipeline. The pipeline runner needs to support Docker. You can run themvn verify
Maven (or gradle verify
if you are using Gradle) locally or in your pipeline.
Use case #2: what about the API gateway?
Until now, we have only been testing our application together with the upstream services. What about the downstream ones?
The strategy is the same: add it to your Docker compose file.
You need to add an extra configuration because the API Gateway running inside a Docker container will access the application running on the host machine. In my example, the value added in the Docker Compose file is proxy-host:host-gateway
.
gateway:
build:
context: .
dockerfile: gateway/Dockerfile
extra_hosts:
- proxy-host:host-gateway
ports:
- '9090:9090'
I'm building a Docker image from a Maven module project in the example below. This module is a stub from the real gateway. This is nice because I don't have the complexity of pushing my image to a central repository. It's easier to update it if necessary and see the impact right after. This is the Dockerfile:
FROM maven:3.9.6-eclipse-temurin-17 AS build
WORKDIR /app
ADD ../ /app/
RUN mvn clean verify -pl gateway
FROM openjdk:17-jdk-bullseye
COPY --from=build /app/gateway/target/*.jar /app.jar
EXPOSE 9090
ENTRYPOINT java -jar /app.jar
The last change needed is that instead of calling your application directly in your tests, you will call the API Gateway. So, change the port from 8080
to 9090
.
Use case #3: what about third-party services?