How to make the junit tests use the embedded mongoDB in a springboot application?

16,122

An alternative would be to run entire spring boot application in test. In this case your spring boot application will be discovered automatically and embedded mongoDB will be downloaded and started by Spring Boot

@RunWith(SpringRunner.class)
@SpringBootTest
public class YourSpringBootApplicationTests {

08:12:14.676 INFO EmbeddedMongo:42 - note: noprealloc may hurt performance in many applications 08:12:14.694 INFO EmbeddedMongo:42 - 2017-12-31T08:12:14.693+0200 I CONTROL [initandlisten] MongoDB starting : pid=2246 port=52299 08:12:22.005 INFO connection:71 - Opened connection [connectionId{localValue:2, serverValue:2}] to localhost:52299

In case of your example you might modify the code in order to start embedded Mongo on different port:

  1. add test/resoures/test.properties file in order to override properties from application.properties

    mongo.db.name=person_testDB
    mongo.db.url=localhost
    mongo.db.port=12345
    
  2. modify MongoDBConfig: add MONGO_DB_PORT field

    @EnableMongoRepositories
    public class MongoDBConfig {
        @Value("${mongo.db.url}")
        private String MONGO_DB_URL;
    
        @Value(("${mongo.db.port:27017}"))
        private int MONGO_DB_PORT;
    
        @Value("${mongo.db.name}")
        private String MONGO_DB_NAME;
    
        @Bean
        public MongoTemplate mongoTemplate() {
            MongoClient mongoClient = new MongoClient(MONGO_DB_URL, MONGO_DB_PORT);
            MongoTemplate mongoTemplate = new MongoTemplate(mongoClient, MONGO_DB_NAME);
            return mongoTemplate;
        }
    }
    
  3. modify test class: remove @DataMongoTest annotation. This annotation forces starting embedded mongoDB instance

    static MongodExecutable mongodExecutable;
    
    @BeforeClass
    public static void setup() throws Exception {
        MongodStarter starter = MongodStarter.getDefaultInstance();
        String bindIp = "localhost";
        int port = 12345;
        IMongodConfig mongodConfig = new MongodConfigBuilder()
                .version(Version.Main.PRODUCTION)
                .net(new Net(bindIp, port, Network.localhostIsIPv6()))
                .build();
        mongodExecutable = null;
        try {
            mongodExecutable = starter.prepare(mongodConfig);
            mongodExecutable.start();
        } catch (Exception e){
            // log exception here
            if (mongodExecutable != null)
                mongodExecutable.stop();
        }
    }
    
    @AfterClass
    public static void teardown() throws Exception {
        if (mongodExecutable != null)
            mongodExecutable.stop();
    }
    

One more way is to use MongoRepository and init embedded Mongo as part of test @Configuration class: it's outlined here: How do you configure Embedded MongDB for integration testing in a Spring Boot application?

Share:
16,122
SkyBlue
Author by

SkyBlue

Updated on July 20, 2022

Comments

  • SkyBlue
    SkyBlue almost 2 years

    I am learning springboot and have created a simple springboot application. I want it to use the embedded mongoDB when it runs the unit tests and the external mongoDB for the rest of the application. However it uses the external mongoDB for the unit tests instead of the embedded one. I have following two dependencies in my POM.

        <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>
            <scope>test</scope>
        </dependency>
    

    my properties file has the following:

    # MongoDB properties
    mongo.db.name=person_testDB
    mongo.db.url=localhost
    
    #external Mongo url
    spring.data.mongodb.uri=mongodb://localhost:27017/personDB
    

    I have a config file(MongoDBConfig.java) which includes embedded MongoDB configurations:

    @EnableMongoRepositories
    public class MongoDBConfig {
    
    @Value("${mongo.db.url}")
    private String MONGO_DB_URL;
    
    @Value("${mongo.db.name}")
    private String MONGO_DB_NAME;
    
    @Bean
    public MongoTemplate mongoTemplate() {
        MongoClient mongoClient = new MongoClient(MONGO_DB_URL);
        MongoTemplate mongoTemplate = new MongoTemplate(mongoClient, MONGO_DB_NAME);
        return mongoTemplate;
     }
    }
    

    Following is my PersonService.java class:

    @Service
    public class PersonService  {
    private static final Logger logger = LoggerFactory.getLogger(PersonService.class);      
    @Autowired
    MongoTemplate mongoTemplate;            
    public void savePerson(Person person) {
        String name = person.getName();
        String collectionName = name.substring(0, 1);
            mongoTemplate.save(person, collectionName);
        }               
    }
    

    My unit test for the PersonsService class is as follows:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = {MongoDBConfig.class})
    @SpringBootTest(classes = PersonService.class)
    @DataMongoTest
    public class PersonServiceTest {
    
    @Autowired
    PersonService personService;    
    MongodForTestsFactory factory;
    MongoClient mongo;
    
    @Before
    public void setup() throws Exception {
        factory = MongodForTestsFactory.with(Version.Main.PRODUCTION);
        mongo = factory.newMongo();
    }
    
    @After
    public void teardown() throws Exception {
        if (factory != null)
            factory.shutdown();
    }
    
    @Test
    public void testSave(){
    Person person = new Person("Bob Smith " , 25);
    personService.savePerson(person);
    }
    }
    

    It creates the collection name and the document name correctly in the external MongoDB which is not what I want. How can I restrict the unitTests to an embedded Mongo?