Spring Boot + DataMongoTest: Testing MongoDB Repositories with Embedded MongoDB (Flapdoodle)

Introduction

The @DataMongoTest annotation in Spring Boot is designed for isolated testing of MongoDB repositories. It automatically configures an embedded MongoDB instance using Flapdoodle, which eliminates the need for a real database.

By default, @DataMongoTest:

  • Automatically configures an in-memory MongoDB instance (Flapdoodle).
  • Loads only MongoDB-related components (documents, repositories, etc.).
  • Rolls back changes after each test, keeping the database clean.
  • Excludes unnecessary beans (@Service, @Controller), making tests lightweight.

This approach allows fast and isolated repository testing without setting up an external MongoDB instance.

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 – Includes JUnit, AssertJ, and Mockito.
  • Flapdoodle Embedded MongoDB – Provides an in-memory MongoDB instance for testing.

Spring Boot Testing Libraries

The spring-boot-starter-test dependency includes:

  • JUnit – Core testing framework.
  • Spring Boot Test – Utilities for integration testing.
  • AssertJ – Fluent assertion library.
  • Mockito – A powerful mocking framework.

Implementation

1. pom.xml Configuration

<?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-spring-boot-testing-example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>datamongodb-spring-boot-testing-example</name>
    <description>Demo project for Spring Boot</description>
    <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>de.flapdoodle.embed</groupId>
            <artifactId>de.flapdoodle.embed.mongo.spring30x</artifactId>
            <version>4.6.2</version>
            <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 – Provides all necessary testing libraries.
  • de.flapdoodle.embed.mongo.spring30x – Automatically sets up an embedded MongoDB instance for tests.

2. Embedded MongoDB Configuration

Since @DataMongoTest automatically configures Flapdoodle, no explicit database configuration is needed.

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 Embedded MongoDB

Using Flapdoodle for MongoDB Repository Testing

Spring Boot automatically configures Flapdoodle Embedded MongoDB for @DataMongoTest, so we don’t need to start an external database.

File: src/test/java/.../repository/DeviceRepositoryTest.java

package tech.devblueprint.datamongodb_spring_boot_testing_example.repository;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import tech.devblueprint.datamongodb_spring_boot_testing_example.document.Device;

import java.util.Arrays;

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

@DataMongoTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS) // Allows non-static @BeforeAll method
public class DeviceRepositoryTest {

    @Autowired
    private DeviceRepository deviceRepository;

    @BeforeAll
    void setUp() {
        // Save initial devices into the embedded MongoDB database
        Device device1 = new Device("1", "SmartphoneX", "Smartphone", "ManufacturerA");
        Device device2 = new Device("2", "LaptopY", "Laptop", "ManufacturerB");
        Device device3 = new Device("3", "TabletZ", "Tablet", "ManufacturerA");
        deviceRepository.saveAll(Arrays.asList(device1, device2, device3));
    }

    @Test
    void findByName_ReturnsDevice() {
        // Retrieve device by name
        Device device = deviceRepository.findByName("SmartphoneX").orElse(null);
        assertThat(device).isNotNull();
        assertThat(device.getName()).isEqualTo("SmartphoneX");
        assertThat(device.getType()).isEqualTo("Smartphone");
        assertThat(device.getManufacturer()).isEqualTo("ManufacturerA");
    }
}

Key Annotations Explained:

  • @DataMongoTest – Loads only MongoDB-related components for testing.
  • @TestInstance(TestInstance.Lifecycle.PER_CLASS) – Allows using a non-static @BeforeAll method to initialize test data.
  • @BeforeAll – Inserts initial test data into the embedded MongoDB before running tests.
  • @Test – Defines a test case that retrieves a device by name.

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 an embedded MongoDB instance (Flapdoodle) instead of a real MongoDB database.