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
Tokenizing a String But Ignoring Delimiters Within Quotes
What Is the Point of Overloaded Convenience Factory Methods for Collections in Java 9
Concurrentmodificationexception When Adding Inside a Foreach Loop in Arraylist
Why I Can't Create an Array with Large Size
How to Simulate Keyboard Presses in Java
How to Get the Latest Jre/Jdk as a Zip File Rather Than Exe or Msi Installer
How to Increase Ide Memory Limit in Intellij Idea on MAC
Why There Is No Concurrenthashset Against Concurrenthashmap
How to Access Parameters in a Restful Post Method
Is String Literal Pool a Collection of References to the String Object, or a Collection of Objects
How to Sort an Arraylist Using Multiple Sorting Criteria
Incompatible Magic Value 1008813135
Jsch Algorithm Negotiation Fail
How to Fix Ambiguous Type on Method Reference (Tostring of an Integer)
How to Call Oracle Stored Procedure Which Include User-Defined Type in Java