introduce

Testing is an integral part of software development. It is common for programmers to run code while making changes to test their application to make sure it behaves as they want. With the right test setup, this process can even be automated, saving a lot of time. Running tests consistently after writing new code ensures that new changes do not break pre-existing functionality. This gives developers confidence in their code base, especially when it is deployed in production so that users can interact with it.

Mocha is a popular JavaScript testing framework.

In this article, you’ll write tests for the Node.js TODO list module. Will walk you through building your tests using the Mocha testing framework. Then use the Node.jsAssert module to create your own tests.

A prerequisite for

  • Node.js(This tutorial uses Node.js version 10.16.0.)

Step 1 – Write the node module

First, we need to set up the coding environment. Create a folder in terminal with your project name. This tutorial will use the name todos:

mkdir todos
Copy the code

Then go to that folder:

cd todos
Copy the code

Initialize NPM now because we will use its CLI functionality to run tests later:

npm init -y
Copy the code

We have only one dependency, Mocha, which we will use to organize and run our tests. To download and install Mocha, use the following command:

npm i request --save-dev mocha
Copy the code

We installed Mocha as a Dev dependency because it is not required by the module in production.

Finally, let’s create a file that contains the module code:

touch index.js
Copy the code

With this, we are ready to create our module. Index.js opens in a text editor, such as nano:

nano index.js
Copy the code

Let’s start by defining the Todos class. This class contains all the functionality we need to manage the TODO list. Add the following lines to index.js:

todos/index.js

class Todos {
    constructor() {
        this.todos = []; }}module.exports = Todos;
Copy the code

We create a Todos class as an entry point. Its constructor() function takes no arguments, so we do not need to provide any values to instantiate an object for this class. When we initialize a Todos object, all we do is create the properties of an empty array of Todos.

This modules line allows other Node.js modules to require our Todos class. Let’s add a function that returns todos the array we stored.

// todos/index.js
class Todos {
    constructor() {
        this.todos = [];
    }
    
    list() {
        return[...this.todos]; }}module.exports = Todos;
Copy the code

Our list() function returns a copy of the array used by the class. It uses JavaScript’s deconstruction syntax to make copies of arrays.

Note: JavaScript arrays are reference types. This means that for any variable assignment to an array or function call that takes an array as an argument, JavaScript references the original array created. For example, if we have an array of three items, x, and create a new variable, y, and both refer to the same thing. Any changes we make to the array with impact variables, and vice versa. y = x“y“x“y“x

Now let’s write the add() function and add a new TODO item:

todos/index.js

class Todos {
    constructor() {
        this.todos = [];
    }
    
    list() {
        return [...this.todos];
    }
    
    add(title) {
        let todo = {
            title: title,
            completed: false,}this.todos.push(todo); }}module.exports = Todos;
Copy the code

Our add() function takes a string and places it in the title property of a new JavaScript object. The new object also has a completed property, which is false by default. We then add this new object to our TODO array.

An important function in the TODO manager is to mark projects as completed. For this implementation, we will traverse our TODOS array to find the TODO item the user is searching for. If found, we mark it as completed. If not, we throw an error.

Add the complete() function like this:

todos/index.js

class Todos {
    constructor() {
        this.todos = [];
    }
    
    list() {
        return [...this.todos];
    }
    
    add(title) {
        let todo = {
            title: title,
            completed: false,}this.todos.push(todo);
    }
    
    complete(title) {
        let todoFound = false;
        this.todos.forEach((todo) = > {
            if (todo.title === title) {
                todo.completed = true;
                todoFound = true;
                return; }});if(! todoFound) {throw new Error(`No TODO was found with the title: "${title}"`); }}}module.exports = Todos;
Copy the code

Save the file and exit the text editor.

We now have a basic TODO manager that we can experiment with. Next, let’s test our code manually to see if the application works.

Step 2 – Test the code manually

In this step, we run the code’s function and observe the output to make sure it meets our expectations. This is called manual testing. This is probably the most common test method used by programmers. Although we’ll use Mocha to automate our tests later, we’ll test our code manually first to better understand how manual tests differ from test frameworks.

Let’s add two TODO items to our application and mark one of them as done. Start index.js in the folder where the file is located:

node
Copy the code

You’ll > see a prompt in the REPL telling us that we can enter JavaScript code. Type the following at the prompt:

const Todos = require('./index');
Copy the code

Using require(), we load the TODOs module into a TODOs variable. Recall that our module Todos returns classes by default.

Now, let’s instantiate an object for this class. In the REPL, add this line of code:

const todos = new Todos();
Copy the code

We can use this toDOS object to verify that our implementation is valid. Let’s add our first TODO item:

todos.add("run code");
Copy the code

So far, we haven’t seen any output in the terminal. Let’s verify that we have stored our “run Code “TODO item by getting a list of all toDos:

todos.list();
Copy the code

You’ll see this output in your REPL:

Output
[ { title: 'run code'.completed: false}]Copy the code

This is the expected result: we have a TODO entry in our TODO array, which is not completed by default.

Let’s add another TODO item:

todos.add("test everything");
Copy the code

Mark the first TODO project as completed:

todos.complete("run code");
Copy the code

Our Todos object will now manage two projects: “Run code” and” Test Everything “. TODO will also “run code”. List () let’s call it again to confirm this:

todos.list();
Copy the code

The REPL will print:

Output
[
  { title: 'run code'.completed: true },
  { title: 'test everything'.completed: false}]Copy the code

Now, exit the REPL with the following command:

.exit
Copy the code

So far you can see that the test module we created behaves as expected. While we didn’t put our code into test files or use test libraries, we did test our code manually. However, this form of testing became time-consuming every time we made a change. Next, let’s solve this problem using the Mocha testing framework in Node.js.

See below for how to test node.js modules using Mocha and Assert (middle)