Test Data

One of the most challenging aspects of writing advanced automated tests is providing your tests with reliable test data. Especially if you are writing a database-driven application - you can write tests that check response, but how do you make sure that database had the data that tests expect?

Nodebootstrap uses a database migrations system that can greatly assist here. The basic idea is that we can write migration scripts that insert reliable test data in a database, thus ensuring that our tests run against expected data in all developer environments and in integration (ci/cd) environment. There is a bit of a trick required to make it work, however, which we explain below.

Environment-Specific Migrations

By default, migrations generated with make migration-create run in any environment. If we just use them our test data will be created in all environments including production and some other environments where we may not wan them. So we need to tell our migrations, that create test data, to only run in specific environments.

To do so, in the javascript file for the migration, in both "up" and "down" functions, you need to add a snippet of code that looks like the following:

const allowed = ["dev", "qa"];
if (!allowed.includes(db.internals.argv.env)) {
console.log(`Environment ${db.internals.argv.env} is not ${allowed}. Skipping ${filePath}`);
return new Promise( function( resolve, reject ) { resolve(""); });
}

Which tells db-migrate to skip the migrations for any environment except for "dev" and "cicd" environments.

You normally would want to add this code after the line declaring the filePath variable. You may also choose to analyze disallowed environments, rather than allowed ones, in which case the end result will look something like the following:

exports.up = function(db) {
var filePath = path.join(__dirname, 'sqls', '20171120013239-sample-user-data-up.sql');
const disallowed = ["production", "staging"];
if (disallowed.includes(db.internals.argv.env)) {
console.log(`Environment ${db.internals.argv.env} is one of disallowed: ${disallowed}. Skipping ${filePath}`);
return new Promise( function( resolve, reject ) { resolve(""); });
}
// ... rest of the up function
}
exports.down = function(db) {
var filePath = path.join(__dirname, 'sqls', '20171120013239-sample-user-data-down.sql');
const disallowed = ["production", "staging"];
if (disallowed.includes(db.internals.argv.env)) {
console.log(`Environment ${db.internals.argv.env} is one of disallowed: ${disallowed}. Skipping ${filePath}`);
return new Promise( function( resolve, reject ) { resolve(""); });
}
// ... rest of the down function
}

You can see example environment-specific migration in NodeBootstrap: https://github.com/inadarei/nodebootstrap-microservice/blob/master/migrations/20170420012051-create-users-table.js#L21 Please note that to execute db-migrate in environment-aware mode, we also had to make following mods to the Makefile:

  1. Add environment-detection at the top of the Makefile

  2. Execute db-migration in environment-specific mode, in the db migrate target.

We have also submitted a ticket to db-migrate authors, proposing a solution that makes environment-specific migrations tad bit less tedious: https://github.com/db-migrate/node-db-migrate/issues/536

Feel free to visit db-migrate's issue queue to vote on the proposal, or help with the code, if you would like to see the solution implemented, but even meanwhile: using environment-specific migrations is a very effective way of writing complex, reliable automated tests.

We hope you enjoy this feature of Nodebootstrap/db-migrate and that it helps you build more reliable software.