This library simplifies integration tests for Node.js applications that use MongoDB. It starts a local MongoDB process with the mongodb-memory-server library and runs it in in-memory mode, which keeps your tests fast.
Since running embedded mongo takes some time, we need to config mocha to wait until mongo is up and running, the easiest way to do it add --delay flag for mocha and handle async flow, like this
//package.json
...
"scripts": {
...
"test": "mocha ./**/*.spec.js --delay",
...
},
...
add init.spec.js
//init.spec.js
const mongoUnit = require('mongo-unit')
mongoUnit.start().then(() => {
console.log('fake mongo is started: ', mongoUnit.getUrl())
process.env.DATABASE_URL = mongoUnit.getUrl() // this var process.env.DATABASE_URL = will keep link to fake mongo
run() // this line start mocha tests
})
after(() => {
const dao = require('./dao')
console.log('stop')
dao.close()
return mongoUnit.stop()
})Code under test
//dao.js
const mongoose = require('mongoose')
const userSchema = new mongoose.Schema({
name: String,
})
const taskSchema = new mongoose.Schema({
userId: String,
task: String,
})
module.exports = {
init: () => mongoose.connect(process.env.DATABASE_URL),
close: () => mongoose.disconnect(),
User: mongoose.model('user', userSchema),
Task: mongoose.model('task', taskSchema),
}Test data
{
"users": [
{
"_id": "56d9bf92f9be48771d6fe5b1",
"name": "test"
},
{
"_id": "56d9bf92f9be48771d6fe5b2",
"name": "John"
}
],
"tasks": [
{
"userId": "56d9bf92f9be48771d6fe5b1",
"task": "do stuff"
},
{
"userId": "56d9bf92f9be48771d6fe5b1",
"task": "fix stuff"
}
]
}Mocha test
//dao.spec.js
const {expect} = require('chai')
const mongoUnit = require('mongo-unit')
const testData = require('./data.json')
const daoUT = require('./dao')
describe('dao', ()=>{
before(() => daoUT.init())
beforeEach(() => mongoUnit.load(testData))
afterEach(() => mongoUnit.drop())
it('should find all users', () => {
return daoUT.User.find()
.then(users => {
expect(users.length).to.equal(2)
expect(users[0].name).to.equal('test')
})
})
it('should find all tasks for user 1', () => {
return daoUT.User.find()
.then(users => users[0])
.then(user=>daoUT.Task.find({userId: user._id}))
.then(tasks => {
expect(tasks.length).to.equal(2)
expect(tasks[0].task).to.equal('do stuff')
})
})
})I was inspired by dbUnit library, which is very popular in java world.
There is alternative library for mocking Mongo: mockgoose
It works on Node.js 12+
npm install -D mongo-unit
docker build -t mongo-unit .
docker run -it mongo-unit
It starts mongod on one of available port and returns Promise with URL to connect to this db.
opts is optional params, you can specify some command line params for mongod:
opts.port- preferable mongo db port, default:27017opts.dbName- name of test db, default:testopts.dbpath- db path, default:<node_modules/mongo-unit>\.mongo-unitopts.verbose- enable debug logs, default:falseopts.version- specify which version of mongo to download. e.g.version=v3.6opts.useReplicaSet- specify we want to start the memory server as aMongoMemoryReplSetneeded to support transactions, default:falseopts.storageEngine- specify the Mongo storage engine to use (e.g.,wiredTiger); default: non-replica setephemeralForTest, replica setwiredTiger. (Note that as of Mongo 7+,ephemeralForTestis no longer supported or allowed, so you will have to specify an option here.)
mongodb-memory-server can also be configured via environment variables.
For instance, export MONGOMS_DEBUG=1will activate debug logging in the memory server. See their docs for more information.
It stops mongod process
Syncronius API returns URL to connect to test db, if test DB is not started it thows an Exception
Inserts given data into DB collections, returns Promise. Data can be provided in two formats:
-
Simple array of documents (backward compatible):
{ "collectionName1":[ {"field1":"value1"}, {"field2":"value2"} ], "collectionName2":[ {"field3":"value3"}, {"field4":"value4"} ] } -
Object with
indexesanddocuments(to define required indexes explicitly in fixture data):{ "users": { "indexes": [ { "key": { "email": 1 }, "name": "email_unique_idx", "unique": true }, { "key": { "name": 1 }, "name": "name_idx" } ], "documents": [ { "name": "Test User", "email": "test@example.com" } ] } }
This object form lets you declare any indexes that the fixture data needs (for example, unique indexes used to test duplicate-key behavior). All indexes for all collections are created first, and only then are the documents inserted, so the indexes are enforced against the fixture data itself.
Note: mongo-unit does not read or infer indexes from Mongoose schemas (or any other schema definition). You have to declare the indexes you want in the fixture data explicitly.
If indexes or documents is provided but is not an array, load() rejects with a clear error so that typos such as indicies or document do not silently leave the collection empty. createIndexes() is only called when indexes is a non-empty array.
Clear collections based on given data (data format is the same), returns Promise.
Drops test DB, returns Promise.
Helper function to load database data into Mongo. Accepts the same data formats as load(data), including the { indexes, documents } object form for declaring required indexes in fixture data.
helper function, clear all db data from mongo