Testing nodejs background jobs

The majority of web applications may not need a background job, but for those that do, experience some level of shadow around testing/debugging and discovering issues before it becomes too late. This article contributes towards increasing testability and saving time for late debugging.

As it was in other blogs that preceded this one, we will explore some of the ways to make sure most of the parts are accessible for testability.

In this article we will talk about:

Even though this blog post was designed to offer complementary materials to those who bought my Testing nodejs Applications book, the content can help any software developer to tuneup working environment. You use this link to buy the book. Testing nodejs Applications Book Cover

Show me the code


//Job Definition in jobs/email.js
var email = require('some-lib-to-send-emails'); 
var User = require('./models/user.js');

module.exports = function(agenda) {
  
  agenda.define('registration email', function(job, done) {
    User.findById(job.attrs.data.userId, function(err, user) {
       if(err) return done(err);
       	var message = ['Thanks for registering ', user.name, 'more content'].join('');
      	return email(user.email, message, done);
     });
  });

  agenda.define('reset password', function(job, done) {/* ... more code*/});
  // More email related jobs
};
//triggering in route.js
//lib/controllers/user-controller.js
var app = express(),
    User = require('../models/user-model'),
    agenda = require('../worker.js');

app.post('/users', function(req, res, next) {
  var user = new User(req.body);
  user.save(function(err) {
    if(err) return next(err);
    //@todo - Schedule an email to be sent before expiration time
    //@todo - Schedule an email to be sent 24 hours
    agenda.now('registration email', { userId: user.primary() });
     return res.status(201).json(user);
  });
});

Example:

What can possibly go wrong?

When trying to figure out how to approach testing delayed asynchronous nodejs background jobs, the following points may be a challenge:

It is easy to fall into the integration testing trap when testing nodejs background jobs. Not only those jobs are asynchronous, but also are scheduled to run at a particular time. The following are additional challenges when testing nodejs background jobs in a Unit Test context.

Choosing tools

If you haven't already, reading “How to choose the right tools” blog post gives insights on a framework we used to choose the tools we suggest in this blog.

Following our own Choosing the right tools framework, we suggest adopting the following tools, when testing nodejs background, or scheduled, tasks:

Workflow

What should I be testing

If you haven't already, read the “How to write test cases developers will love”

Istanbul generates reports as tests progress.

# In package.json at "test" - add next line
$ istanbul test mocha -- --color --reporter mocha-lcov-reporter specs
# Then run the tests using 
$ npm test --coverage 

Example:

Show me the tests

If you haven't already, read the “How to write test cases developers will love”

It is a little bit challenging to test a function that is not accessible outside its definition closure. However, making the function definition accessible from outside the library makes it possible to test the function in isolation.


describe('Jobs', () => {

  it('should define registration email', done => {
   registrationEmailTask(params, (attrs) => {
     expect(User.findById).toHaveBeenCalled(); 
     expect(email).toHaveBeenCalled();
     done();
   });
   
  });

});

Following the same footsteps, we can test the reset password task. To learn more about mocking database functions, please read this article.

There is a chapter on testing background jobs in the book, for more techniques to mock, modularize and test background jobs.

The lens to test the application from counts more at this level. A misstep makes us fall into integration testing territory, un-willingly.

Conclusion

Automated testing of any JavaScript project is quite intimidating for newbies and veterans alike. In this article, we reviewed how testing tends to be more of art, than science.

We also stressed the fact that, like in any art, practice makes perfect ~ testing background jobs constitutes some of the challenging tasks from the asynchronous nature of the jobs. There are additional complimentary materials in the “Testing nodejs applications” book.

References

#snippets #code #annotations #question #discuss