Spring Boot Testcontainers Example

In this tutorial, we will create a sample Spring Boot API that uses MongoDB as its database and then demonstrate how to use Testcontainers to write integration tests for the API. Testcontainers is a powerful Java library that allows you to spin up and manage Docker containers during your test runs, making it ideal for testing applications that rely on external services like databases.

Prerequisites

Before getting started, make sure you have the following prerequisites:

  1. Java Development Kit (JDK) 8 or higher installed on your system.
  2. Apache Maven or Gradle installed (we will use Maven in this tutorial).
  3. Docker installed and running on your system.

Create a Spring Boot Application

Let’s start by creating a new Spring Boot project. You can use the Spring Initializer, a web-based tool, or your preferred IDE to create the project. Make sure to include the following dependencies:

  • Spring Web
  • Spring Data MongoDB
  • Lombok (optional but useful for reducing boilerplate code)

For this tutorial, we’ll name our project “SpringBootTestcontainersExample.”

Implement a Sample API

Next, let’s implement a simple RESTful API that interacts with a MongoDB database. Create a Book class representing a book entity:

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Data
@Document
public class Book {
    @Id
    private String id;
    private String title;
    private String author;
}

Now, create a repository for the Book class:

import org.springframework.data.mongodb.repository.MongoRepository;

public interface BookRepository extends MongoRepository<Book, String> {
}

Next, create a controller to handle HTTP requests:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/books")
public class BookController {
    private final BookRepository bookRepository;

    @Autowired
    public BookController(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }

    @GetMapping
    public List<Book> getAllBooks() {
        return bookRepository.findAll();
    }

    @PostMapping
    public Book createBook(@RequestBody Book book) {
        return bookRepository.save(book);
    }
}

Your basic Spring Boot application with MongoDB integration is now ready.

Add Testcontainers Dependency

To use Testcontainers in your project, you need to add the testcontainers dependency to your pom.xml (if using Maven) or build.gradle (if using Gradle). Here’s the Maven dependency:

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>testcontainers</artifactId>
    <version>1.16.3</version> <!-- Replace with the latest version -->
    <scope>test</scope>
</dependency>

Make sure to use the latest version of Testcontainers.

Write Integration Tests

Now, let’s write integration tests using Testcontainers to ensure our Spring Boot API interacts correctly with a MongoDB container.

Create a test class in the src/test/java directory (e.g., BookControllerIntegrationTest.java) and add the following code:

import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.testcontainers.containers.MongoDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@Testcontainers
public class BookControllerIntegrationTest {

    @LocalServerPort
    private int port;

    @Autowired
    private MockMvc mockMvc;

    @Container
    private static final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:latest"))
            .withExposedPorts(27017);

    @BeforeAll
    public static void setUp() {
        mongoDBContainer.start();
    }

    @AfterAll
    public static void tearDown() {
        mongoDBContainer.stop();
    }

    @Test
    public void testCreateBook() throws Exception {
        String requestBody = "{\"title\":\"Test Book\",\"author\":\"Test Author\"}";

        mockMvc.perform(MockMvcRequestBuilders.post("http://localhost:" + port + "/books")
                .content(requestBody)
                .contentType("application/json"))
                .andExpect(status().isOk());

        mockMvc.perform(MockMvcRequestBuilders.get("http://localhost:" + port + "/books"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.length()").value(1))
                .andExpect(jsonPath("$[0].title").value("Test Book"))
                .andExpect(jsonPath("$[0].author").value("Test Author"));
    }
}

In this test class:

  • We use @Testcontainers to indicate that we will be using Testcontainers in our tests.
  • We create a MongoDB container using MongoDBContainer and expose port 27017.
  • In the setUp and tearDown methods, we start and stop the MongoDB container.
  • The testCreateBook method sends a POST request to create a book and then verifies that the book was successfully created by sending a GET request to retrieve all books.

Run the Tests

You can now run your integration tests by executing the following command from the project’s root directory:

mvn test

Testcontainers will automatically start a MongoDB Docker container, run your tests, and then clean up the container after the tests are finished.

Congratulations! You have successfully created a Spring Boot API, integrated MongoDB, and used Testcontainers to write integration tests for your application.

This tutorial provides a basic example, but you can extend it to test other parts of your application that rely on external services using Testcontainers.