Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing with MongoDB

My database of choice is MongoDB. I'm writing a data-layer API to abstract implementation details from client applications - that is, I'm essentially providing a single public interface (an object which acts as an IDL).

I'm testing my logic as I go in a TDD manner. Before each unit test, an @Before method is called to create a database singleton, after which, when the test completes, an @After method is called to drop the database. This helps to promote independence among unit tests.

Nearly all unit tests, i.e. performing a contextual query, require some kind of insertion logic to occur before hand. My public interface provides an insert method - yet, it seems incorrect to use this method as precursor logic to each unit test.

Really I need some kind of mocking mechanism, yet, I haven't had much experience with mocking frameworks, and it seems that Google returns nothing re a mocking framework one might use with MongoDB.

What do others do in these situations? That is, how do people unit test code that interacts with a database?

Also, my public interface connects to a database defined in a external configuration file - it seems incorrect to use this connection for my unit testing - again, a situation that would benefit from some kind of mocking?

like image 847
wulfgarpro Avatar asked Sep 14 '11 09:09

wulfgarpro


People also ask

Can unit tests use database?

Unit tests shouldn't depend on infrastructureThere's no way to test this function without a database connection available at the time of testing. If a new developer clones the project they will need to set up a database before they can successfully run the unit tests.

What is MongoDB testing?

If you are using Rational® Integration Tester V9. 5.0 or later, you can create MongoDB transports and run tests against them. MongoDB is an open source, document-oriented NoSQL database. MongoDB is different from traditional SQL-based relational databases.

Can I debug unit test?

You can use Test Explorer to start a debugging session for your tests. Stepping through your code with the Visual Studio debugger seamlessly takes you back and forth between the unit tests and the project under test.

What is unit testing with real time example?

An example of a real-world scenario that could be covered by a unit test is a checking that your car door can be unlocked, where you test that the door is unlocked using your car key, but it is not unlocked using your house key, garage door remote, or your neighbour's (who happen to have the same car as you) key.


2 Answers

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.

like image 111
sbridges Avatar answered Sep 28 '22 08:09

sbridges


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 injection svc.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.

like image 40
rit Avatar answered Sep 28 '22 08:09

rit