In this article, I will give a simple illustration of what unit testing is as well as show you how to unit test functions in JavaScript with Mocha and Chai.
Before we dive into the technical part of Unit testing, let’s consider a scenario:
Imagine that you are helping your little sibling work on her assignment. In her assignment, she is told to mix together a group of colours which will eventually rise to the Green colour.
After doing a bit of research, you find out that a mixture of blue, red and green paint will eventually give rise to the black colour.
You proceed to the store to buy the three colours of paint you need. Each of the paint is stored in a translucent container which has the colour as it’s label. Now you can just start mixing up the three colours. You have to be sure that each colour (aka unit) is the right shade needed. So, you drop test each colour by dropping a little on white cloth and inspecting it’s look.
If that particular colour matches to your desired colour, then that test is said to be passed. If not, then the test has failed. If all tests passed, which means that all a colours are correct, then you can be rest assured that mixing together the three of them will indeed give rise to black.
You can say that the black is made up of 3 units: The green, the blue and the red. Before mixing up the three colours and submitting the homework, you made sure to test every of it’s unit to make sure it gives the expected output.
UNIT TESTING IN SOFTWARE DEVELOPMENT
Before any software is released into the market, it has to be vigorously tested.
Software testing is the process of examining for the accuracy, completeness and quality of computer software before it gets released to the market. It is geared towards checking for errors(bugs) and fixing those errors.
Unit testing is the most foundational level of software testing. In this level of testing, individual functionality, modules, procedures or even lines of code within the larger application are tested in isolation to make sure they work correctly or give the expected output on their own.
WHY IS UNIT TESTING IMPORTANT?
Running unit tests gives you a very granular perspective of how your application works. Since you understand how the individual pieces work on its own, you have far more control over your application.
At that level, it is far easier to change or integrate more functionality because it is at a very basic level.
Unit tests are also faster to perform, faster than other levels of testing. Since you are testing very minute units, and not interconnected parts or even whole systems, you can run lots of tests in a very short amount of time.
UNIT TESTING IN JAVASCRIPT
In JavaScript, you can run unit test on individual modules. Unit tests can be run using test frameworks. Some of the most popular testing frameworks:
- Mocha (with Chai)
- Jest
- Jasmine
and many others.
All of these frameworks are basically the same. Whatever difference they may have lies mostly in their syntax. Most of these testing frameworks use the expect syntax. Expect is a popular language for making test assertions.
Chai is an assertion library which supports the Expect syntax.
Here are some of the main methods supported by Chai. Here you pass in the actual values—as returned by the module/function—to expect() and use the following
methods to compare those returned values with your expected values which you hardcoded in the tests:
function add() {
return 2+2;
}
expect(add()).to.be(4) // Expects the value to be equal with JavaScript’s triple equal sign === (checks for value and type, not just value)
expect(add()).to.equal(4) // Expects the value to be deep-equal
Object.prototype.b = 2;
let obj = {a: 1, c: 3}
expect(obj).to.have.property(b) // Expects obj to have property (b) either on it or on the prototype object
expect(obj).to.have.own.property(b) // Expects obj to have property (b) physically defined in it
expect(obj).to.have.any.keys(b, c) // Expects obj to have any of the keys (b or c) defined on it
expect('foo').to.be.a('string'); // Expects value to be of string type
expect({a: 1}).to.be.an('object'); // Expects value to be of object type
expect(null).to.be.a('null'); // Expects value to be of null type
expect(undefined).to.be.an('undefined');// Expects value to be undefined type
expect(new Error).to.be.an('error'); //Expects value to be of Error type
expect(Promise.resolve()).to.be.a('promise'); // Expects value to be of promise type
You can visit the Chai API documentation to see the full BDD syntax and test combinations.
SETTING UP YOUR TESTING PROJECT
To start this project, you need to have node and npm installed. You can install them here. Next, we will need to initialize our project.
To do this, we go to the command line and run the following command:
npm init project-name
This command will create a project named project-name (replace with your own name) inside the current directory. If you already have a directory you want to use instead, navigate to that folder and run the following command:
npm init
Running any of those two commands will generate a package.json file for your project. Go with the default options and skip some of the fields don’t understand.
Next, we are going to install our test frameworks. In this tutorial, we will be using Mocha and Chai.
To install both these frameworks, we go over to our command line and run the following command:
npm install –-save -dev mocha chai
The –save-dev flag is used to install them as a dev dependency, because we will not be using the tests in production mode, just when developing. You typically install test frameworks as a dev dependency.
With our dependencies now all set, we have to create two folders in the root directory:
/libraries
: This folder will contain the modules/functions we want to unit test/test
: This folder will contain the corresponding tests for each of the modules we want to test
It’s now time to write some tests!
UNIT TEST EXAMPLE WITH MOCHA
Our first test will be to test for the strict equality of a function’s return value. We do this with to.be.equal()
method. In this test, we create a function which takes in a word and returns it in uppercase.
First we need to create the module in the libraries folder of our project:
module.exports = function capitalize(word) {
return word.toUpperCase();
}
/* FOLDER
/libraries/capitalize.js
Next, we need to write a test for this module. This test checks to see if the capitalized name returned by the above module is strictly equal to the expected value.
First we will need to import the module we want to unit test, and then we also import the Expect utility from chai.
var capitalize = require('../libraries/capitalize')
var expect = require('chai').expect
describe("#capitalize", function () {
it ("capitalizes the first word in a string", function() {
expect(capitalize("hello")).to.equal("HELLO")
})
})
/* FOLDER
/test/capitalize.test.js
You are have probably already made what does constructs do, but in case you are feeling a bit lost, let me break it down a bit:
Describe()
is used to define the test suite, which is just a set of tests we are going to run together
It()
is used to create and describe a test case, describing what that case is going to test for.
Also, the capitalize.test.js is a naming convention for tests. That is, the test.js is added to the actual name of the module to be tested, which in this case is capitalize
Next, we need run the test. To do this, we navigate to our project directory and run the following command:
./node_modules/.bin/mocha
// This should return the following result on the command line:
#capitalize
 capitalizes the first word in a string
1 passing (22ms)
/* This indicates that the test was passed and the value returned by capitalize is strictly equal (===) to the value we passed.*/
Assuming we altered the expected value a bit, like so:
describe("#capitalize", function () {
it ("capitalizes the first word in a string", function() {
expect(capitalize("hello")).to.equal("HALLO")
})
})
Running the same command will give the following result:
#capitalize
1) capitalizes the first word in a string
0 passing (41ms)
1 failing
1) #capitalize
capitalizes the first word in a string:
AssertionError: expected 'HELLO' to equal 'HALLO'
+ expected - actual
-HELLO
+HALLO
at Context.<anonymous> (test\capitalize.tests.js:6:37)
at processImmediate (internal/timers.js:456:21)
/* This indicates that the test had failed. Why? Because HELLO is not strictly equal to HALLO (HELLO !==HALLO)*/
The error information returned also provides us with detailed info about what actually went wrong and the precise line number where we can find the problem in our script.
Now, you don’t have to run the following command on your terminal anytime you want to execute a test:
./node_modules/.bin/mocha
You can easily automate this task by inserting the following script into your package.json file:
{
"name": "testing",
"version": "1.0.0",
"description": "a simple test tutorial with mocha and chai ",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"testing"
],
"author": "kingsley uabh",
"license": "ISC",
"devDependencies": {
"chai": "^4.3.4",
"mocha": "^9.0.3"
}
}
//BEFORE EDITING
{
"name": "testing",
"version": "1.0.0",
"description": "a simple test tutorial with mocha and chai ",
"main": "index.js",
"scripts": {
"test": "./node_modules/.bin/mocha"
},
"keywords": [
"testing"
],
"author": "kingsley uabh",
"license": "ISC",
"devDependencies": {
"chai": "^4.3.4",
"mocha": "^9.0.3"
}
}
After editing. Replace the value inside test field.
This is how we can run simple unit tests with a testing framework like Mocha and Chai. You can use other kinds of assertions to create a wide variety of tests.
WRAPPING UP
Software testing is a very important process which all applications must go through before getting released to end users.
Unit testing is the most basic level of software testing. It involves the testing of an isolated chunk of functionality or procedure to make sure that it behaves the way it is expected to.
In JavaScript, unit testing can be carried out with testing frameworks. One of the popular choice for that is Mocha. Mocha is usually used alongside Chai to implement BDD assertions.
I hope you got something useful from this article.
YOU MIGHT ALSO LIKE:
Thank you for reading and see you soon.
Top comments (0)