Unit Testing in JavaScript with Mocha

Test-driven development (TDD) is an approach to development that consists of writing tests, followed by production code, and refactoring as needed. The tests are written to fail initially, and the developer writes code to fulfill the requirements of the test so they pass.

In this tutorial, we'll learn how to implement the TDD process by developing a simple command line calculator app from scratch with Node.js. In case you're unfamiliar, Node.js allows the use of JavaScript on the server side. Read the getting started article to get up to speed with Node.js. We're going to set up tests with Mocha, a testing framework, for this app.

You'll also learn how to use the built-in readline module in Node.js to send commands to the program via the command line.

Setting Up Our Environment

Since our application runs in Node.js, we will need to set up a local environment for our files and dependencies.

Create a new directory called calc. In the command prompt, navigate to the directory and initialize a new project using npm init, which will create a new package.json file for our program.

npm init

You will be prompted to enter the package name, version, description, and other common package details. We can enter the name calc.js, and continue along pressing ENTER for all the default items, giving a description if you'd like. When you reach test command, type mocha, which is the testing framework we will be using.

test command: mocha

Continue entering the defaults until the walkthrough is complete. The script will create a package.json file that looks like this:

The test is passing as expected, so our testing environment setup is complete. Remove everything except the first line from test.js.

test.js

const assert =require('assert')

test.js is the file we will use for testing throughout the creation of our app. Let's create two additional files: operations.js for our arithmetic and validation functions, and calc.js for our app itself. We want to keep our files separate so they don't get too long and complex. Below is our list of files.

calc.js

node_modules

operations.js

package-lock.json

package.json

test.js

From here, we will begin adding our first actual test for the application.

Adding Mathematical Operations

The first requirement for our application is that it should add, subtract, divide, and multiply any two numbers. This means we'll have to create a function for each of those mathematical operations.

Let's start with addition. We will write a test to calculate the sum of two numbers that we know will be true. The below code is testing if 1 plus 3 equals 4 in the add() function.

The test has failed, giving us the following information: ReferenceError: add is not defined. We're testing the add() function which does not exist yet, so this error makes perfect sense.

In operations.js, we're going to create the add() function.

operations.js

constadd=(x, y)=>+x ++y

The add() function takes two arguments (x and y) and returns their sum. You may notice that it is written as (+x) + (+y) instead of x + y. We are using the unary operator to coerce the parameters into numbers in case the input is a string.

Now we have a working function, and our test passes as expected. Since the other arithmetic functions all follow the same pattern, we can make tests for subtract(), multiply(), and divide(), as well as one to test negative integers.

test.js

it('correctly calculates the sum of 1 and 3',()=>{
assert.equal(operations.add(1,3),4)})it('correctly calculates the sum of -1 and -1',()=>{
assert.equal(operations.add(-1,-1),-2)})it('correctly calculates the difference of 33 and 3',()=>{
assert.equal(operations.subtract(33,3),30)})it('correctly calculates the product of 12 and 12',()=>{
assert.equal(operations.multiply(12,12),144)})it('correctly calculates the quotient of 10 and 2',()=>{
assert.equal(operations.divide(10,2),5)})

> mocha
✓ correctly calculates the sum of 1 and 3
✓ correctly calculates the sum of -1 and -1
✓ correctly calculates the difference of 33 and 3
✓ correctly calculates the product of 12 and 12
✓ correctly calculates the quotient of 10 and 2
5 passing (8ms)

All of our tests are passing, so now we can be sure that the main objectives of our application will function properly. Moving forward, we will add some extra validation.

Adding Validation

Right now, if the user enters any number and selects an operation, everything works as expected. However, what would happen if they tried to find the sum of a number and a string✓ The application would attempt to do the calculation, but as it's expecting numbers, the output would be NaN, or Not a Number.

Instead of just returning strange output, we want to fill the second goal of our application - that it should display a warning and exit if it receives any input that is not a number.

First, we'll have to create a function that tests whether the input is a number or not. The application will take two numbers, so we'll test three things: if both inputs are a number, if only one is a number, and if neither one is a number.

test.js

it('indicates failure when a string is used instead of a number',()=>{
assert.equal(operations.validateNumbers('sammy',5),false)})it('indicates failure when two strings is used instead of numbers',()=>{
assert.equal(operations.validateNumbers('sammy','sammy'),false)})it('successfully runs when two numbers are used',()=>{
assert.equal(operations.validateNumbers(5,5),true)})

Our validateNumbers() function will test both parameters. The isNaN() function will check if the parameters are not numbers, and will return false if so. Otherwise it will return true, and the validation will be successful.

Make sure to add validateNumbers to the module.exports at the bottom of the file. Now we can run our new tests.

npmtest

1) indicates failure when a string is used instead of a number
✓ indicates failure when two strings is used instead of numbers
✓ successfully runs when two numbers are used
7 passing (12ms)
1 failing
1) indicates failure when a string is used instead of a number:
AssertionError [ERR_ASSERTION]: true == false
+ expected - actual
-true
+false

Two of them passed, but one failed. Testing for success on two numbers passed, as well as testing for failure on two strings. Our first validation test, one string and one number, failed.

Looking back at our function, it requires that both parameters must be NaN to fail. We want it to fail even if only one parameter is NaN, so we will change && to ||.

✓ indicates failure when a string is used instead of a number
✓ indicates failure when two strings is used instead of numbers
✓ successfully runs when two numbers are used
8 passing (9ms)

All of the functionality of our application has been tested. The functions have been proven to successfully do mathematical operations and validate input. The final step is creating the interface for the user.

Creating Final Command Line Interface

We have the necessary functions to do arithmetic and validate, but there is currently no way for a user to access these functions. It will be necessary to utilize an interface. A user interface can be a graphical user interface (GUI) or command line interface (CLI). We are going to make our application using a command line interface.

Currently, our calc.js file is empty. This is where our application is going to live. To begin, we will pull in the functions from operations.js.

calc.js

const operations =require('./operations.js')

Our interface itself will use the Readline module, a built-in Node.js CLI.

calc.js

const readline =require('readline')

Now that we're pulling in all our requirements, we can begin building the app. We will access readline through the rl variable to create the interface.

The first thing we'll want the user to see when they run the program is the initial welcome screen, which tells them what they've opened, and the instructions for usage. We will do this with a console.log().

calc.js

console.log(`
Calc.js
Welcome to the Node.js Calculator app!
Version: 1.0.0.
Usage: The user will be prompted for two numbers,
then asked to select their operation of choice.
`)

Before we get started with the actual functionality of the calculator, let's test of our console.log() is working properly. We'll make our app print out the message, then exit. readline will use the rl.close() method to exit.

calc.js

rl.close()

To run a command line application with node, you will type node followed by the filename.

node calc.js

Calc.js
Welcome to the Node.js Calculator app!
Version: 1.0.0.
Usage: The user will be prompted for two numbers,
then asked to select their operation of choice.

Our welcome screen displays, then the program terminates. The next step will be to take some user input. We're going to require three in total: two numbers, and a choice of operation. We will request each input with the rl.question() method.

Our first number will be entered with the parameter of x, the second number with y, and the operation selection with choice. At this point, running the program will request the desired input, but won't do anything with it.

After our third question, the first thing we'll want to do is validate the input to ensure only numbers are being entered. We're going to reference the validateNumbers() function. Using the logical NOT operator, we will test if the parameter values are not numbers, and end the program if so.

If all input is valid and correct, we will want to move forward with the process and run the respective mathematical operations that we created earlier. We will use a switch statement to execute code based on the four possible choices, and output the result of the operation. If an invalid choice is made, the default code block will run, telling the user to start over.

calc.js

if(!operations.validateNumbers(x, y)){
console.log('Only numbers are allowed! Please restart the program.')}else{switch(choice){case'1':
console.log(`The sum of ${x} and ${y} is ${operations.add(x, y)}.`)breakcase'2':
console.log(`The difference of ${x} and ${y} is ${operations.subtract(x, y)}.`)breakcase'3':
console.log(`The product of ${x} and ${y} is ${operations.multiply(x, y)}.`)breakcase'4':
console.log(`The quotient of ${x} and ${y} is ${operations.divide(x, y)}.`)breakdefault:
console.log('Please restart the program and select a number between 1 and 4.')break}}

Note: The console.log() functions are utilizing template literals, a type of string that allows expressions and variables to be embedded in the string. For more information, learn how to work with strings in JavaScript.

Everything went through successfully and our output was as expected. Congratulations! You have successfully created a simple calculator application with Node.js, and learned the basics of the test-driven development methodology along the way.

Conclusion

If you missed anything or got stuck along the way, you can find the source code on GitHub.

We just covered the basics of test-driven development through the creation of a command line calculator app in Node.js. We used the Mocha framework for testing, and the built-in Node.js Readline module for creating a command line interface.

One option moving forward would be to test and implement new features of the calculator, such as adding the ability to square a number or find the remainder, or you could implement a looping method for the calculator to ask if the user would like to do another calculation after completing one.

Join the newsletter

I write about JavaScript, programming, and front-end design. Join over 6,000 other developers in keeping up with my content. Unsubscribe whenever. Never any spam, ads, or affiliate links.

I'm Tania, a full-stack software developer specializing in modern JavaScript. I make
open source coding projects and write free, quality articles and tutorials that help
thousands of people daily. No ads, no sponsored posts, no bullshit.