18

I'm trying to write a test to test a method that connects to mongo, but I don't actually want to have to have mongo running and actually make a connection to it to have my tests pass successfully.

Here's my current test which is successful when my mongo daemon is running.

describe('with a valid mongo string parameter', function() {
    it('should return a rejected promise', function(done) {
        var con = mongoFactory.getConnection('mongodb://localhost:27017');
        expect(con).to.be.fulfilled;
        done();
    });
});

mongoFactory.getConnection code:

getConnection: function getConnection(connectionString) {

      // do stuff here

        // Initialize connection once
        MongoClient.connect(connectionString, function(err, database) {
          if (err) {
            def.reject(err);
          }

          def.resolve(database);
        });

      return def.promise;
    }
Catfish
  • 18,876
  • 54
  • 209
  • 353
  • One good reason why i want this is that my unit tests all rely on actually connecting to mongo so they fail if mongod is not running. Which means they all fail when built on travis ci for instance. – Catfish Sep 01 '14 at 23:46
  • possible duplicate of: http://stackoverflow.com/questions/12526160/mocking-database-in-node-js and http://stackoverflow.com/questions/10378116/mock-test-mongodb-database-node-js – zamnuts Sep 02 '14 at 03:43
  • no experience with this, but at first glance Sinon.JS might help using stubs and mocks: https://www.npmjs.org/package/sinon – zamnuts Sep 19 '14 at 10:20

2 Answers2

44

There are a couple of SO answers related to unit testing code that uses MongoDB as a data store:

I'll make an attempt at consolidating these solutions.

Preamble

First and foremost, you should want MongoDB to be running while performing your tests. MongoDB's query language is complex, so running legitimate queries against a stable MongoDB instance is required to ensure your queries are running as planned and that your application is responding properly to the results. With this in mind, however, you should never run your tests against a production system, but instead a peripheral system to your integration environment. This can be on the same machine as your CI software, or simply relatively close to it (in terms of process, not necessarily network or geographically speaking).

This ENV could be low-footprint and completely run in memory (resource 1) (resource 2), but would not necessarily require the same performance characteristics as your production ENV. (If you want to performance test, this should be handled in a separate environment from your CI anyway.)

Setup

  • Install a mongod service specifically for CI. If repl sets and/or sharding are of concern (e.g. write concern, no use of $isolated, etc.), it is possible to mimic a clustered environment by running multiple mongod instances (1 config, 2x2 data for shard+repl) and a mongos instance on the same machine with either some init.d scripts/tweaks or something like docker.
  • Use environment-specific configurations within your application (either embedded via .json files, or in some place like /etc, /home/user/.your-app or similar). Your application can load these based on a node environment variable like NODE_ENV=int. Within these configurations your db connection strings will differ. If you're not using env-specific configs, start doing this as a means to abstract the application runtime settings (i.e. "local", "dev", "int", "pre", "prod", etc.). I can provide a sample upon request.
  • Include test-oriented fixtures with your application/testing suite. As mentioned in one of the linked questions, MongoDB's Node.js driver supports some helper libraries: mongodb-fixtures and node-database-cleaner. Fixtures provide a working and consistent data set for testing: think of them as a bootstrap.

Builds/Tests

  1. Clean the associated database using something like node-database-cleaner.
  2. Populate your fixtures into the now empty database with the help of mongodb-fixtures.
  3. Perform your build and test.
  4. Repeat.

On the other hand...

If you still decide that not running MongoDB is the correct approach (and you wouldn't be the only one), then abstracting your data store calls from the driver with an ORM is your best bet (for the entire application, not just testing). For example, something like model claims to be database agnostic, although I've never used it. Utilizing this approach, you would still require fixtures and env configurations, however you would not be required to install MongoDB. The caveat here is that you're at the mercy of the ORM you choose.

Community
  • 1
  • 1
zamnuts
  • 9,492
  • 3
  • 39
  • 46
-2

You could try tingodb.

TingoDB is an embedded JavaScript in-process filesystem or in-memory database upwards compatible with MongoDB at the API level.

Alex Lapa
  • 1,149
  • 11
  • 21
  • 2
    From tingodb's README: "Upwards compatible means that if you build an app that uses functionality implemented by TingoDB you can switch to MongoDB almost without code changes." This means, if you're using MongoDB, you can't switch to TingoDB. – zamnuts Jul 04 '16 at 20:13
  • 3
    No, it means that not all features implemented by MongoDB are supported by TingoDB, but most common subset is there. That's why I specifically said "try" tingodb. – Alex Lapa Jul 05 '17 at 02:32