Unit testing with MongoDB Unit testing with MongoDB mongodb mongodb

Unit testing with MongoDB


Technically tests that talk to a database (nosql or otherwise) are not unit tests, as the tests are testing interactions with an external system, and not just testing an isolated unit of code. However tests that talk to a database are often extremely useful, and are often fast enough to run with the other unit tests.

Usually I have a Service interface (eg UserService) which encapsulates all the logic for dealing with the database. Code that relies on UserService can use a mocked version of UserService and is easily tested.

When testing the implementation of the Service that talks to Mongo, (eg MongoUserService) it is easiest to write some java code that will start/stop a mongo process on the local machine, and have your MongoUserService connect to that, see this question for some notes.

You could try to mock the functionality of the database while testing MongoUserService, but generally that is too error prone, and doesn't test what you really want to test, which is interaction with a real database. So when writing tests for MongoUserService, you set up a database state for each test. Look at DbUnit for an example of a framework for doing so with a database.


As sbridges wrote in this post it is a bad idea not to have a dedicated service (sometimes also known as repository or DAO) which abstracts the data access from the logic. Then you could test the logic by providing a mock of the DAO.

Another approach which I do is to create a Mock of the Mongo object (e.g. PowerMockito) and then return the appropriate results.This because you don't have to test if the database works in unit tests but more over you should test if the right query was sent to the databse.

Mongo mongo = PowerMockito.mock(Mongo.class);DB db = PowerMockito.mock(DB.class);DBCollection dbCollection = PowerMockito.mock(DBCollection.class);PowerMockito.when(mongo.getDB("foo")).thenReturn(db);PowerMockito.when(db.getCollection("bar")).thenReturn(dbCollection);MyService svc = new MyService(mongo); // Use some kind of dependency injectionsvc.getObjectById(1);PowerMockito.verify(dbCollection).findOne(new BasicDBObject("_id", 1));

That would also be an option. Of course the creation of the mocks and returning of the appropriate objects is just coded as an example above.


I wrote a MongoDB fake implementation in Java: mongo-java-server

Default is a in-memory backend, that can be easily used in Unit and Integration tests.

Example

MongoServer server = new MongoServer(new MemoryBackend());// bind on a random local portInetSocketAddress serverAddress = server.bind();MongoClient client = new MongoClient(new ServerAddress(serverAddress));DBCollection coll = client.getDB("testdb").getCollection("testcoll");// creates the database and collection in memory and inserts the objectcoll.insert(new BasicDBObject("key", "value"));assertEquals(1, collection.count());assertEquals("value", collection.findOne().get("key"));client.close();server.shutdownNow();