How to Integrate Embedded MongoDB for Unit Testing in a Spring Application
Tags: springboot, java, webdev, mongodb
Published: 2024-06-23 17:41:25

Unit testing is a crucial part of software development, ensuring that individual components of an application work as expected. When it comes to testing data persistence layers in a Spring application, MongoDB is a popular choice. To facilitate unit testing with MongoDB, we can use an embedded MongoDB instance. This eliminates the need for an actual running MongoDB server, making tests more reliable and easier to set up.

In this blog, we will walk through the steps required to integrate embedded MongoDB into a Spring application for unit testing.

## Table of Contents

1. [Introduction](#introduction)
2. [Prerequisites](#prerequisites)
3. [Setting Up the Project](#setting-up-the-project)
4. [Adding Dependencies](#adding-dependencies)
5. [Configuring Embedded MongoDB](#configuring-embedded-mongodb)
6. [Creating a Repository](#creating-a-repository)
7. [Writing Unit Tests](#writing-unit-tests)
8. [Running the Tests](#running-the-tests)
9. [Conclusion](#conclusion)

## Introduction

Embedded MongoDB allows developers to run a MongoDB server embedded within the Java application, specifically for testing purposes. This ensures that tests are run in isolation and are not dependent on an external MongoDB instance. By using embedded MongoDB, we can simulate a real MongoDB environment and perform integration tests on our repositories.

## Prerequisites

Before we begin, ensure you have the following installed on your system:
- Java Development Kit (JDK) 8 or later
- Maven or Gradle build tool
- An Integrated Development Environment (IDE) like IntelliJ IDEA or Eclipse

## Setting Up the Project

First, create a new Spring Boot project using Spring Initializr or your preferred method. Ensure that you include `Spring Data MongoDB` as a dependency.

## Adding Dependencies

To use embedded MongoDB, we need to add the `de.flapdoodle.embed.mongo` dependency to our project. Additionally, we will add Spring Data MongoDB for interacting with MongoDB.

If you are using Maven, add the following dependencies to your `pom.xml` file:

```xml
<dependencies>
    <!-- Spring Data MongoDB -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
    
    <!-- Embedded MongoDB -->
    <dependency>
        <groupId>de.flapdoodle.embed</groupId>
        <artifactId>de.flapdoodle.embed.mongo</artifactId>
        <version>3.2.1</version>
    </dependency>
    
    <!-- Spring Boot Test -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
```

For Gradle, add the following dependencies to your `build.gradle` file:

```groovy
dependencies {
    // Spring Data MongoDB
    implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
    
    // Embedded MongoDB
    testImplementation 'de.flapdoodle.embed:de.flapdoodle.embed.mongo:3.2.1'
    
    // Spring Boot Test
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
```

## Configuring Embedded MongoDB

Next, we need to configure Spring to use the embedded MongoDB instance during tests. Create a configuration class for this purpose.

```java
package com.example.demo;

import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoClientDbFactory;

import de.flapdoodle.embed.mongo.MongodExecutable;
import de.flapdoodle.embed.mongo.MongodStarter;
import de.flapdoodle.embed.mongo.config.IMongodConfig;
import de.flapdoodle.embed.mongo.config.MongodConfigBuilder;
import de.flapdoodle.embed.mongo.config.Net;
import de.flapdoodle.embed.mongo.distribution.Version;

import java.io.IOException;

@TestConfiguration
public class EmbeddedMongoConfig {

    @Bean
    public MongodExecutable embeddedMongoServer() throws IOException {
        IMongodConfig mongodConfig = new MongodConfigBuilder()
                .version(Version.Main.PRODUCTION)
                .net(new Net("localhost", 27017, true))
                .build();

        MongodStarter starter = MongodStarter.getDefaultInstance();
        return starter.prepare(mongodConfig);
    }

    @Bean
    public MongoTemplate mongoTemplate() throws IOException {
        embeddedMongoServer().start();
        return new MongoTemplate(new SimpleMongoClientDbFactory("mongodb://localhost:27017/test"));
    }
}
```

This configuration class sets up an embedded MongoDB instance that runs on `localhost` at port `27017`.

## Creating a Repository

Create a simple repository interface to interact with MongoDB. For this example, let's assume we have a `User` entity.

```java
package com.example.demo.repository;

import com.example.demo.model.User;
import org.springframework.data.mongodb.repository.MongoRepository;

public interface UserRepository extends MongoRepository<User, String> {
}
```

Create the `User` entity:

```java
package com.example.demo.model;

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

@Document
public class User {

    @Id
    private String id;
    private String name;
    private String email;

    // Constructors, getters, and setters
}
```

## Writing Unit Tests

Now, let's write unit tests to verify the functionality of the `UserRepository`. We'll use Spring's testing support to load the application context and the embedded MongoDB instance.

```java
package com.example.demo;

import com.example.demo.model.User;
import com.example.demo.repository.UserRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;

import java.util.Optional;

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

@SpringBootTest
@Import(EmbeddedMongoConfig.class)
@ActiveProfiles("test")
public class UserRepositoryTests {

    @Autowired
    private UserRepository userRepository;

    @Test
    public void testSaveAndFindUser() {
        User user = new User();
        user.setName("John Doe");
        user.setEmail("john.doe@example.com");

        userRepository.save(user);

        Optional<User> foundUser = userRepository.findById(user.getId());
        assertThat(foundUser).isPresent();
        assertThat(foundUser.get().getName()).isEqualTo("John Doe");
        assertThat(foundUser.get().getEmail()).isEqualTo("john.doe@example.com");
    }
}
```

## Running the Tests

Run the tests using your IDE or build tool. The embedded MongoDB instance will start automatically before the tests and shut down after the tests are completed.

If using Maven, run the tests with:

```sh
mvn test
```

If using Gradle, run the tests with:

```sh
gradle test
```

## Conclusion

Integrating embedded MongoDB into a Spring application for unit testing provides a convenient and efficient way to test MongoDB-related functionality without the need for an external MongoDB server. By following the steps outlined in this blog, you can set up and use embedded MongoDB in your Spring application, ensuring your data persistence layer is thoroughly tested.

Using embedded MongoDB ensures that your tests are isolated, repeatable, and easy to manage, leading to more robust and reliable applications.