ellman121
ellman121

Reputation: 1835

Mocha Unit Testing Mongoose Models

I'm struggling to figure out the correct (i.e. not a hack) way to write these unit tests for my NodeJS app.

In server.js, I connect mongoose to the DB running on localhost:27017. When I run my mocha tests, I would like to connect to a different mongoDB instance running on localhost:37017, so that I am not running my tests against a live database. When I require mongoose in test.js and try to connect, mongoose throws an error, saying "Trying to open unclosed connection."

I have tried closing the current connection in test.js, however it doesn't work for some reason.

My question is: What is the proper way to connect to a test DB in one file, but continue letting server.js connect to the live DB?

My code is below:

// test.js
var app = require('../lib/server') // This connects mongoose to a database
var assert = require('assert');
var httpstatus = require('http-status');
var superagent = require('superagent');

// Connect to mongoose
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:37017/testDB'); // THIS THROWS ERROR because server.js is connecting to localhost:27017/liveDB

// Models we will be testing
var thing = require('../models/thing.js');

describe('Thing', function() {

    before(function() {
        // Clear the database here
    }

    beforeEach(function() {
        // Insert, modify, set up records here
    }

    it('saves the thing to the database', function() {
        // Save and query a thing here (to the test DB)
    });
});

Upvotes: 1

Views: 1363

Answers (2)

Yilmaz
Yilmaz

Reputation: 49182

npm i env-cmd --save   // install this package

create config directory in the root of the project and create dev.env and test.env files in the config folder.

in test.env file, configure your test environment like this:

PORT=4000

MONGODB_URL=mongodb://127.0.0.1:27017/dbTestName

then in the package.json, load the settings of test.env into the test environment.

"test": "env-cmd  -f ./config/test.env jest --watchAll --runInBand"

here we required the module and then loaded the test.env settings here.

env-cmd package will add all the settings from the .env files into process.env object depending on your environment. when you run run npm test, your app will use the settings inside the test.env.

so in your application this is how you should use the MONGODB_URL to connect mongoose.

mongoose
  .connect(process.env.MONGODB_URL, {
    useNewUrlParser: true,
    useCreateIndex: true,
    useFindAndModify: false
  })
  .catch(err => {
    console.log(err.message);
    process.exit(1);
  })
  .then(() => {
    console.log("connected to mongodb");
  });

you will use settings inside the dev.env for your dev environment. Now you need to tweak the dev script inside the package.json

"dev": "env-cmd -f ./config/dev.env node src/index.js",

now when you run

npm run dev

your app load the settings from the dev.env

Upvotes: 0

robertklep
robertklep

Reputation: 203231

You could try this (although it's a hack):

// Connect to mongoose
var mongoose = require('mongoose');
before(function(done) {
  mongoose.disconnect(function() {
    mongoose.connect('mongodb://localhost:37017/testDB');
    done();
  });
});

// Models we will be testing (see text)
var thing = require('../models/thing.js');

...

describe(...)

It might be necessary to load your model inside the disconnect handler as well, as it may "attach" to the original connection otherwise.

Again, this is still quite a hack, and I would suggest moving the configuration of your database to an external configuration file of some sorts, or use an environment variable, which could be relatively easy to implement:

// server.js
mongoose.connect(process.env.MONGO_URL || 'mongodb://localhost:27017/prodDB')

// test.js
process.env.MONGO_URL = 'mongodb://localhost:37017/testDB'
var app = require('../lib/server');

Upvotes: 1

Related Questions