Embedded Mongodb When Running Integration Tests

Embedded MongoDB when running integration tests

Here's an updated (for 2022) version of the accepted answer from @rozky (a lot has been changed in both the Mongo and Embedded MongoDB libraries).

package com.example.mongo;

import com.mongodb.BasicDBObject;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import de.flapdoodle.embed.mongo.MongodExecutable;
import de.flapdoodle.embed.mongo.MongodProcess;
import de.flapdoodle.embed.mongo.MongodStarter;
import de.flapdoodle.embed.mongo.config.MongodConfig;
import de.flapdoodle.embed.mongo.config.Net;
import de.flapdoodle.embed.mongo.distribution.Version;
import de.flapdoodle.embed.process.runtime.Network;
import java.util.Date;
import org.junit.After;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;

public class EmbeddedMongoTest {

private static final String DATABASE_NAME = "embedded";

private MongodExecutable mongodExe;
private MongodProcess mongod;
private MongoClient mongo;

@Before
public void beforeEach() throws Exception {
MongodStarter starter = MongodStarter.getDefaultInstance();
String bindIp = "localhost";
int port = 12345;
MongodConfig mongodConfig = MongodConfig.builder()
.version(Version.Main.PRODUCTION)
.net(new Net(bindIp, port, Network.localhostIsIPv6()))
.build();
this.mongodExe = starter.prepare(mongodConfig);
this.mongod = mongodExe.start();
this.mongo = new MongoClient(bindIp, port);
}

@After
public void afterEach() throws Exception {
if (this.mongod != null) {
this.mongod.stop();
this.mongodExe.stop();
}
}

@Test
public void shouldCreateNewObjectInEmbeddedMongoDb() {
// given
MongoDatabase db = mongo.getDatabase(DATABASE_NAME);
db.createCollection("testCollection");
MongoCollection<BasicDBObject> col = db.getCollection("testCollection", BasicDBObject.class);

// when
col.insertOne(new BasicDBObject("testDoc", new Date()));

// then
assertEquals(1L, col.countDocuments());
}

}

EmbedMongo for integration testing

I was looking for transaction support to rollback the changes while doing testing my app written in Spring+RESt+Mongo 2.4. But its not possible since we cant use transaction for mongodb.

Transactions aren't supported, but you do have a few alternative approaches for rolling back changes while testing:

  • create/reset data as needed during set up or tear down in your unit tests
  • seed your initial data set and start mongod with --syncdelay=0 during your testing so no new data is written to disk (Embedded MongoDB suggests this as a "snapshot" approach)

While searching about integration testing I found few links about embedMongo for doing integration testing. You can also do integration testing by having dedicated mongo db instance running somewhere. What special feature that embed mongo provides?

Embedded MongoDB is a wrapper around the standard MongoDB Server binaries intended to help with unit testing. The "special features" of the wrapper are just functions to start/stop MongoDB instances via your unit tests.

Also see the comments on: Embedded MongoDB when running integration tests.

I didn't find great documentation for it, Is it under Apache license?

The "Embedded MongoDB" source files on GitHub suggest Apache 2.0 license.

The MongoDB server binaries will use the standard MongoDB Server community license, which is AGPL v3.0.

How do you configure Embedded MongDB for integration testing in a Spring Boot application?

EDIT: see magiccrafter's answer for Spring Boot 1.3+, using EmbeddedMongoAutoConfiguration.

If you can't use it for any reason, keep reading.


Test class:

    @RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {
Application.class,
TestMongoConfig.class // <--- Don't forget THIS
})
public class GameRepositoryTest {

@Autowired
private GameRepository gameRepository;

@Test
public void shouldCreateGame() {
Game game = new Game(null, "Far Cry 3");
Game gameCreated = gameRepository.save(game);
assertEquals(gameCreated.getGameId(), gameCreated.getGameId());
assertEquals(game.getName(), gameCreated.getName());
}

}

Simple MongoDB repository:

public interface GameRepository extends MongoRepository<Game, String>     {

Game findByName(String name);
}

MongoDB test configuration:

import com.mongodb.Mongo;
import com.mongodb.MongoClientOptions;
import de.flapdoodle.embed.mongo.MongodExecutable;
import de.flapdoodle.embed.mongo.MongodProcess;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;

@Configuration
public class TestMongoConfig {

@Autowired
private MongoProperties properties;

@Autowired(required = false)
private MongoClientOptions options;

@Bean(destroyMethod = "close")
public Mongo mongo(MongodProcess mongodProcess) throws IOException {
Net net = mongodProcess.getConfig().net();
properties.setHost(net.getServerAddress().getHostName());
properties.setPort(net.getPort());
return properties.createMongoClient(this.options);
}

@Bean(destroyMethod = "stop")
public MongodProcess mongodProcess(MongodExecutable mongodExecutable) throws IOException {
return mongodExecutable.start();
}

@Bean(destroyMethod = "stop")
public MongodExecutable mongodExecutable(MongodStarter mongodStarter, IMongodConfig iMongodConfig) throws IOException {
return mongodStarter.prepare(iMongodConfig);
}

@Bean
public IMongodConfig mongodConfig() throws IOException {
return new MongodConfigBuilder().version(Version.Main.PRODUCTION).build();
}

@Bean
public MongodStarter mongodStarter() {
return MongodStarter.getDefaultInstance();
}

}

pom.xml

        <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<version>1.48.0</version>
<scope>test</scope>
</dependency>

Wiring beans during integration tests with embedded mongo

@DataMongoTest:

Annotation that can be used for a MongoDB test that focuses only on MongoDB components.

Using this annotation will disable full auto-configuration and instead apply only configuration relevant to MongoDB tests.

Try a @SpringBootTest for a "full"/default application context instead.

For general information refer to:

  • https://docs.spring.io/spring-framework/docs/current/reference/html/testing.html#testing

For (auto-)configuration details & refinement to:

  • https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.testing

... setting @DataMongoTest(useDefaultFilters = false) (+ fine tuning include-/excludeFilters) can also do the desired.



Related Topics



Leave a reply



Submit