Spring Boot + DataMongoTest + Testcontainers: Testing MongoDB Repositories with a MongoDB Container

Introduction

The @DataMongoTest annotation in Spring Boot is designed for isolated testing of MongoDB repositories. By default, it configures an embedded MongoDB (Flapdoodle) for testing. However, in real-world scenarios, we might need to test against a real MongoDB instance without installing it locally.

This is where Testcontainers comes in.

What is Testcontainers?

Testcontainers is a Java library that allows running lightweight, disposable containers for databases, message queues, and other dependencies. It is particularly useful for integration testing as it provides:

Real database testing without requiring local installation.
Fresh database instances for each test execution.
Automatic cleanup of containers after tests.
Consistent testing environments across different machines.

Project Setup

To get started, create a Spring Boot project with the following dependencies:

  • Spring Boot Starter Data MongoDB – For working with MongoDB.
  • Spring Boot Starter Test – Provides JUnit, AssertJ, and Mockito.
  • Testcontainers MongoDB – Runs MongoDB in a container.

 

Spring Boot Testing Libraries

The spring-boot-starter-test dependency provides several useful testing tools:

  • JUnit – The core testing framework.
  • Spring Boot Test – Provides utilities for integration testing.
  • AssertJ – Fluent assertion library.
  • Mockito – A mocking framework.
  • Testcontainers – Allows running a real MongoDB database in a container.

Implementation

1. pom.xml Configuration

To use Testcontainers with MongoDB, add the necessary dependencies to pom.xml.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>tech.devblueprint</groupId>
    <artifactId>datamongodb-testcontainers-spring-boot-testing-example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>datamongodb-testcontainers-spring-boot-testing-example</name>
    <description>Demo project for Spring Boot</description>
    <url/>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-testcontainers</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.testcontainers</groupId>
            <artifactId>junit-jupiter</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.testcontainers</groupId>
            <artifactId>mongodb</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Key Dependencies Explained:

  • spring-boot-starter-data-mongodb – Enables MongoDB support.
  • spring-boot-starter-test – Includes essential testing libraries.
  • spring-boot-testcontainers – Enables Testcontainers integration with Spring Boot.
  • org.testcontainers:mongodb – Runs MongoDB in a container.
  • org.testcontainers:junit-jupiter – Integrates JUnit 5 with Testcontainers.

2. Configuring MongoDB Testcontainer

By default, @DataMongoTest starts an embedded MongoDB (Flapdoodle). To use a MongoDB container, we need to:

  1. Start a MongoDB Testcontainer in the test class.
  2. Dynamically provide the MongoDB URI to Spring Boot.

3. Document Definition

File: src/main/java/…/document/Device.java

package tech.devblueprint.datamongodb_spring_boot_testing_example.document;

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

@Document(collection = "devices")
public class Device {

    @Id
    private String id;
    private String name;
    private String type;
    private String manufacturer;

    // Default constructor
    public Device() {
    }

    // Parameterized constructor
    public Device(String id, String name, String type, String manufacturer) {
        this.id = id;
        this.name = name;
        this.type = type;
        this.manufacturer = manufacturer;
    }

    // Getter and Setter for id
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }

    // Getter and Setter for name
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    // Getter and Setter for type
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }

    // Getter and Setter for manufacturer
    public String getManufacturer() {
        return manufacturer;
    }
    public void setManufacturer(String manufacturer) {
        this.manufacturer = manufacturer;
    }
}

4. Repository Interface

File: src/main/java/…/repository/DeviceRepository.java

package tech.devblueprint.datamongodb_spring_boot_testing_example.repository;

import tech.devblueprint.datamongodb_spring_boot_testing_example.document.Device;
import org.springframework.data.mongodb.repository.MongoRepository;
import java.util.Optional;

public interface DeviceRepository extends MongoRepository<Device, String> {

    // Find a device by its name
    Optional<Device> findByName(String name);

Writing Tests with Testcontainers

Using a MongoDB Container in Tests

With @DataMongoTest, we can start a MongoDB container and register its connection details dynamically.

File: src/test/java/…/repository/DeviceRepositoryTestContainersTest.java

package tech.devblueprint.datamongodb_testcontainers_spring_boot_testing_example;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.MongoDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import tech.devblueprint.datamongodb_testcontainers_spring_boot_testing_example.document.Device;
import tech.devblueprint.datamongodb_testcontainers_spring_boot_testing_example.repository.DeviceRepository;

import static org.assertj.core.api.Assertions.assertThat;

@Testcontainers
@DataMongoTest
public class DeviceRepositoryTestContainersTest {

    // Start a MongoDB container with the latest image
    @Container
    static MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:latest");

    // Dynamically set the Spring property for MongoDB URI
    @DynamicPropertySource
    static void setProperties(DynamicPropertyRegistry registry) {
        // This provides the connection string to Spring Boot
        registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl);
    }

    @Autowired
    private DeviceRepository deviceRepository;

    @BeforeEach
    void setUp() {
        // Clean up database and insert test data
        deviceRepository.deleteAll();
        Device device = new Device("20", "TCDevice", "Controller", "TCManufacturer");
        deviceRepository.save(device);
    }

    @Test
    void findByName_ReturnsDevice() {
        // Test retrieval of device by name from MongoDB container
        Device device = deviceRepository.findByName("TCDevice").orElse(null);
        assertThat(device).isNotNull();
        assertThat(device.getType()).isEqualTo("Controller");
        assertThat(device.getManufacturer()).isEqualTo("TCManufacturer");
    }
}

Key Annotations Explained:

  • @Testcontainers – Enables Testcontainers integration.
  • @Container – Defines a MongoDB container that runs for the duration of the test class.
  • @DynamicPropertySource – Registers the container’s MongoDB URI dynamically.
  • @DataMongoTest – Loads only MongoDB-related components for testing.
  • @BeforeEach – Cleans up the database and inserts test data before each test.
  • @Test – Runs the test case for MongoDB repository methods.

Understanding Transactions in @DataMongoTest

Unlike relational databases, MongoDB does not support transactions in the same way as SQL databases. Therefore, @DataMongoTest does not roll back changes automatically.

If needed, you should manually clean up the database before each test:

@BeforeEach
void setUp() {
    deviceRepository.deleteAll();
}

Conclusion

In this guide, we explored how to use @DataMongoTest with Testcontainers to test MongoDB repositories with a real database instance.

Key Takeaways:

✅ Testcontainers provides a real MongoDB instance without requiring local installation.
✅ Automatically starts and stops a MongoDB database for testing.
✅ Dynamically injects database connection properties into Spring Boot.

By following this approach, you can test MongoDB repositories with a real database while keeping your tests fast, isolated, and disposable.