I am trying to write a set of test units for my simple DB layer SimpleDbLayer using nodeunit. I am finding it rather difficult.
Problems:
1) I want to connect to the DB once, and use that connection. I cannot really use setUp and tearDown, as they are run before and after each test. As a "solution", I am using a module-wide variable for the scope (see code below)
2) My simple DB layer has several DB drivers. MongoMixin is only one of them -- I have under development MariaMixin and PostgresMixin. Ideally I would run these tests one for each driver, to see if they work. Is there a good, easy way to do this?
3) I am hitting cases where I make a mistake with the code of my test, and all I get is a complaint about test.done not being detected. Is there any trickery I need to be aware of here?
4) Am I doing anything horribly wrong? (see code)
var
dummy
, declare = require('simpledeclare')
, SimpleDbLayer = require('./SimpleDbLayer')
, MongoMixin = require('./MongoMixin.js')
, mw = require('mongowrapper')
, async = require('async')
;
var db, layer;
exports.createLayer = {
databaseConnect: function( test ){
mw.connect('mongodb://localhost/hotplate', {}, function( err, returnedDb ){
test.ifError( err );
db = returnedDb;
test.done( null );
});
},
makeLayer: function( test ){
var C = declare( [ SimpleDbLayer, MongoMixin ] );
layer = new C( 'test', { name: true, surname: true, age: true }, db );
test.ok( layer );
test.done();
},
deleteAll: function( test ){
layer.delete( { }, { multi: true }, function( err, howmany ){
test.ifError( err );
test.done();
});
},
insert: function( test ){
var people = [
{ name: 'Chiara', surname: 'Mobily', age: 24 },
{ name: 'Tony', surname: 'Mobily', age: 37 },
{ name: 'Sara', surname: 'Connor', age: 14 },
{ name: 'Daniela', surname: 'Mobily', age: 64 },
];
returnedPeople = [];
var functions = [];
// Populate the database
people.forEach( function( person ){
functions.push( function( done ){
layer.insert( person, { returnRecord: true }, function( err, person ){
test.ifError( err );
returnedPeople.push( person );
done( null );
})
})
})
async.series( functions, function( err, res ){
test.ifError( err );
test.done();
});
},
databaseDisconnect: function( test ){
db.close();
test.done();
},
}
Answering myself. The solution is simple: for each driver, this is the test.js file:
var driver = require('./specificDriver'); var simpledblayerTests = require( "./lib/simpledblayer/test.js" );
var tests = simpledblayerTests.get(
function getDbInfo( done ) {
mw.connect('mongodb://localhost/tests', {}, function( err, db ){
if( err ){
throw new Error("MongoDB connect: could not connect to database");
} else {
done( null, db, driver );
}
});
},
function closeDb( db, done ) {
db.close( done );
}
);
for(var test in tests) {
exports[ test ] = tests[ test ];
}
Basically, the get()
function exported by the actual "main" module (more about this later) takes two parameters: two functions that open and close the database connection.
That get()
function returns a bunch of functions ready to be exported -- the functions that make up your unit testings.
The main module will have something like this:
exports.get = function( getDbInfo, closeDb ){
var tests;
var g = {};
var startup = function( test ){
var self = this;
test.doesNotThrow( function(){
getDbInfo( function( err, db, driver ){
if( err ){
throw( new Error("Could not connect to db, aborting all tests") );
process.exit();
}
// Set the important g.driver variables (db and driver)
g.db = db;
d.driver = driver
test.done();
});
});
}
var finish = function( test ){
var self = this;
closeDb( g.db, function( err ){
if( err ){
throw( new Error("There was a problem disconnecting to the DB") );
}
test.done();
});
};
tests = {
startup: startup,
// ...
// Your tests here. All functions will have access to g.db and g.driver
// ...
finish: finish
}
return tests;
}
This way, every single module will run the same tests. However, the driver
variable and the functions to connect/disconnect to the database will be simple.
See it in action with real code: