Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I have a fairly simple Spring Boot application which exposes a small REST API and retrieves data from an instance of MongoDB. Queries to the MongoDB instance go through a Spring Data based repository. Some key bits of code below.

// Main application class @EnableAutoConfiguration(exclude={MongoAutoConfiguration.class, MongoDataAutoConfiguration.class}) @ComponentScan @Import(MongoConfig.class) public class ProductApplication {     public static void main(String[] args) {         SpringApplication.run(ProductApplication.class, args);     } } 
// Product repository with Spring data public interface ProductRepository extends MongoRepository<Product, String> {      Page<Product> findAll(Pageable pageable);      Optional<Product> findByLineNumber(String lineNumber); } 
// Configuration for "live" connections @Configuration public class MongoConfig {      @Value("${product.mongo.host}")     private String mongoHost;      @Value("${product.mongo.port}")     private String mongoPort;      @Value("${product.mongo.database}")     private String mongoDatabase;      @Bean(name="mongoClient")     public MongoClient mongoClient() throws IOException {         return new MongoClient(mongoHost, Integer.parseInt(mongoPort));     }      @Autowired     @Bean(name="mongoDbFactory")     public MongoDbFactory mongoDbFactory(MongoClient mongoClient) {         return new SimpleMongoDbFactory(mongoClient, mongoDatabase);     }      @Autowired     @Bean(name="mongoTemplate")     public MongoTemplate mongoTemplate(MongoClient mongoClient) {         return new MongoTemplate(mongoClient, mongoDatabase);     } } 
@Configuration @EnableMongoRepositories public class EmbeddedMongoConfig {      private static final String DB_NAME = "integrationTest";     private static final int DB_PORT = 12345;     private static final String DB_HOST = "localhost";     private static final String DB_COLLECTION = "products";      private MongodExecutable mongodExecutable = null;      @Bean(name="mongoClient")     public MongoClient mongoClient() throws IOException {         // Lots of calls here to de.flapdoodle.embed.mongo code base to          // create an embedded db and insert some JSON data     }      @Autowired     @Bean(name="mongoDbFactory")     public MongoDbFactory mongoDbFactory(MongoClient mongoClient) {         return new SimpleMongoDbFactory(mongoClient, DB_NAME);     }      @Autowired     @Bean(name="mongoTemplate")     public MongoTemplate mongoTemplate(MongoClient mongoClient) {         return new MongoTemplate(mongoClient, DB_NAME);     }      @PreDestroy     public void shutdownEmbeddedMongoDB() {         if (this.mongodExecutable != null) {             this.mongodExecutable.stop();         }     } } 
@RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = TestProductApplication.class) @IntegrationTest @WebAppConfiguration public class WtrProductApplicationTests {      @Test     public void contextLoads() {         // Tests empty for now     }  } 
@EnableAutoConfiguration(exclude={MongoAutoConfiguration.class, MongoDataAutoConfiguration.class}) @ComponentScan @Import(EmbeddedMongoConfig.class) public class TestProductApplication {      public static void main(String[] args) {         SpringApplication.run(TestProductApplication.class, args);     } } 

So the idea here is to have the integration tests (empty at the moment) connect to the embedded mongo instance and not the "live" one. However, it doesn't work. I can see the tests connecting to the "live" instance of Mongo, and if I shut that down the build simply fails as it is still attempting to connect to the live instance of Mongo. Does anyone know why this is? How do I get the tests to connect to the embedded instance?

like image 675
Jon Avatar asked Jul 22 '15 16:07

Jon


People also ask

What is embedded MongoDB in spring boot?

MongoDB has rapidly gained popularity in the enterprise and the Spring community. While developing and testing Spring Boot applications with MongoDB as the data store, it is common to use the lightweight Embedded MongoDB rather than running a full-fledged server.

Can we connect MongoDB with spring boot?

It's Easy to Connect MongoDB Atlas with Spring Boot Through this article, we demonstrated that MongoDB Spring Boot integration is easy using: Starter data MongoDB artifactid (the dependency we added while creating the Spring Initializr project) in pom. xml. A property on application.

Does spring boot provide MongoDB auto configuration?

Spring Boot provides auto-configuration for Redis, MongoDB, Elasticsearch, Solr and Cassandra; you can make use of the other projects, but you will need to configure them yourself.


2 Answers

Since Spring Boot version 1.3 there is an EmbeddedMongoAutoConfiguration class which comes out of the box. This means that you don't have to create a configuration file at all and if you want to change things you still can.

Auto-configuration for Embedded MongoDB has been added. A dependency on de.flapdoodle.embed:de.flapdoodle.embed.mongo is all that’s necessary to get started. Configuration, such as the version of Mongo to use, can be controlled via application.properties. Please see the documentation for further information. (Spring Boot Release Notes)

The most basic and important configuration that has to be added to the application.properties files is
spring.data.mongodb.port=0 (0 means that it will be selected randomly from the free ones)

for more details check: Spring Boot Docs MongoDb

like image 92
magiccrafter Avatar answered Sep 20 '22 20:09

magiccrafter


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> 
like image 44
cahen Avatar answered Sep 20 '22 20:09

cahen