Unit Testing and Functional Testing: Assert – the basis of testing methodologies

Node.js has a useful built-in testing tool known as the assert module. Its functionality is similar to assert libraries in other languages. Namely, it’s a collection of functions for testing conditions, and if the conditions indicate an error, the assert function throws an exception. It’s not a complete test framework by any stretch of the imagination, but it can still be used for some amount of testing.

At its simplest, a test suite is a series of assert calls to validate the behavior of the thing being tested. For example, a test suite could instantiate the user authentication service, then make an API call and use assert methods to validate the result, then make another API call to validate its results, and so on.

Consider the following code snippet, which you can save in a file named deleteFile.mjs:

import fs from ‘fs’;

export function deleteFile(fname, callback) {

fs.stat(fname, (err, stats) => {

if (err)

callback(new Error(‘the file ${fname} does not exist’));

else {

fs.unlink(fname, err => {

if (err) callback(new Error(‘Could not delete ${fname}’));

else callback();

});

}

});

}

The first thing to notice is this contains several layers of asynchronous callback functions. This presents a couple of challenges:

  • Capturing errors from deep inside a callback
  • Detecting conditions where the callbacks are never called

The following is an example of using assert for testing. Create a file named test- deleteFile.mjs containing the following:

import assert from ‘assert’;

import { deleteFile } from ‘./deleteFile.mjs’;

deleteFile(“no-such-file”, (err) => {

assert.ok(err);

assert.ok(err instanceof Error);

assert.match(err.message, /does not exist/);

});

This is what’s called a negative test scenario, in that it’s testing whether requesting to delete a nonexistent file throws the correct error. The deleteFile function throws an error containing the text that does not exist if the file to be deleted does not exist. This test ensures the correct error is thrown and would fail if the wrong error is thrown, or if no error is thrown.

If you are looking for a quick way to test, the assert module can be useful when used this way. Each test case would call a function, then use one or more assert statements to test the results. In this case, the assert statements first ensure that err has some kind of value, then ensures that value is an Error instance, and finally ensures that the message attribute has the expected text. If it runs and no messages are printed, then the test passes. But what happens if the deleteFile callback is never called? Will this test case catch that error?

$ node test-deleteFile.mjs 

No news is good news, meaning it ran without messages and therefore the test passed.

The assert module is used by many of the test frameworks as a core tool for writing test cases. What the test frameworks do is create a familiar test suite and test case structure to encapsulate your test code, plus create a context in which a series of test cases are robustly executed.

For example, we asked about the error of the callback function never being called. Test frameworks usually have a timeout so that if no result of any kind is supplied within a set number of milliseconds, then the test case is considered an error.

There are many styles of assertion libraries available in Node.js. Later in this chapter, we’ll use the Chai assertion library (http://chaijs.com/), which gives you a choice between three different assertion styles (should, expect, and assert).

Source: Herron David (2020), Node.js Web Development: Server-side web development made easy with Node 14 using practical examples, Packt Publishing.

Leave a Reply

Your email address will not be published. Required fields are marked *