29

I am writing some integration and system tests for my NodeJS application using a MongoDB database. The test framework I use is Mocha and Supertest. Is it possible to setup MongoDB as an in-memory database which I can use to only test which then wipes away all my collections and documents when the test is done?

Rob
  • 26,989
  • 16
  • 82
  • 98
Andreas Selenwall
  • 5,705
  • 11
  • 45
  • 58
  • Not automatically however as @AlexeyOgarkov states there are simple ways to program this, technically it won't be "in memory" since MongoDB is not a memory stored database unlike memcache but it will provide similar functionality. – Sammaye Nov 28 '12 at 15:25
  • It doesn't come with NodeJS support. So it won't work for me. Thanks anyway. – Andreas Selenwall Dec 05 '12 at 21:00
  • 1
    Not memory, but maybe spinning up a [docker container](https://hub.docker.com/_/mongo/) is an option? I've tried to use [mongo-mock](https://www.npmjs.com/package/mongo-mock) in the past, but it's seriously lacking beyond the most basic stuff and I wouldn't recommend wasting time with it. You *should* just use a real 'dev-database' and drop it when you are done. It won't even take a second of your test. – ippi Jul 09 '18 at 02:00
  • 1
    Maybe try this [mongodb-memory-server](https://www.npmjs.com/package/mongodb-memory-server)? (which wasn't around when I worked with the stuff) – ippi Jul 09 '18 at 02:08

2 Answers2

36

You can accomplish this using mongodb-memory-server. The package downloads a mongod binary to your home directory and instantiates a new memory-backed MondoDB instance as needed. For each test file you can spin up a new server which means you can run them all parallel.


For readers using jest and the native mongodb driver, you may find this class useful:

const { MongoClient } = require('mongodb');
const { MongoMemoryServer } = require('mongodb-memory-server');

// Extend the default timeout so MongoDB binaries can download
jest.setTimeout(60000);

// List your collection names here
const COLLECTIONS = [];

class DBManager {
  constructor() {
    this.db = null;
    this.server = new MongoMemoryServer();
    this.connection = null;
  }

  async start() {
    const url = await this.server.getUri();
    this.connection = await MongoClient.connect(url, { useNewUrlParser: true });
    this.db = this.connection.db(await this.server.getDbName());
  }

  stop() {
    this.connection.close();
    return this.server.stop();
  }

  cleanup() {
    return Promise.all(COLLECTIONS.map(c => this.db.collection(c).remove({})));
  }
}

module.exports = DBManager;

Then in each test file you can do the following:

const dbman = new DBManager();

afterAll(() => dbman.stop());
beforeAll(() => dbman.start());
afterEach(() => dbman.cleanup());

I suspect this approach may be similar for other testing frameworks.

David Weldon
  • 63,632
  • 11
  • 148
  • 146
8

I recommend using mongodb-memory-server.

I have a DB file that is shared over the whole project, so I have to have it testable as well.

//db.js

import mongoose from 'mongoose';
import bluebird from 'bluebird';

module.exports = {
  mongoose,
  init: () => {
      mongoose.Promise = bluebird;
  },
  connect: async database => {
      try {
          const conn =  await mongoose.connect(
              database,
              { useNewUrlParser: true }
          );

          //eslint-disable-next-line
          console.log(`MongoDb Connected on: ${database}`);

          return conn;
      } catch (err) {
          //eslint-disable-next-line
          console.log('Error to connect on mongo', err);
      }
  },
  disconnect: async () => await mongoose.connection.close()
};

To be used (db.js) on my tests I've created a test-helper.js file.

'use strict';
import MongodbMemoryServer from 'mongodb-memory-server';
import db from '../src/db';

const server = new MongodbMemoryServer();

const createDB = async () => {
    try {
       const url = await server.getConnectionString();
       db.connect(url);
    } catch (err) {
      throw err;
    }
 };

 const destroyDB = () => {
   db.disconnect();

 };

 module.exports = {
    createDB,
    destroyDB
 }; 
}

So, my tests always have before and after (to create and destroy de DB), something like:

import { createDB, destroyDB } from '../test-helper';
before(() => {
  createDB();
});
after(() => {
  destroyDB();
});

Hope it is helpful.

The project I'm using it: https://github.com/abdalla/node-auth

Carlos
  • 727
  • 7
  • 11