This Mocha unit testing tutorial will help you get started with performing unit testing with the Mocha framework.
OVERVIEW
Software testing is a way to ensure that the software under test (SUT) conforms with the requirements during or after development. It is an important aspect of software engineering as it reduces bugs and deployment of defective software products.
Over the years, different tools have been created to make software testing easy and more fun. These tools have their similarities as well as their differences. Moreover, Mocha is one such tool, and it's a flexible JavaScript testing framework that makes testing simple and more flexible.
In this Mocha unit testing tutorial, we will explore the Mocha JavaScript testing framework with insights into why use the Mocha framework and the different limitations of using Mocha. Lastly, we will learn how to test a demo Node.js application with the Mocha unit testing framework.
Mocha is a JavaScript testing framework that runs both on the server (Node.js) and the client (browser). It's a feature-rich framework that provides on-demand testing tools built-in. Mocha makes asynchronous testing simple and fun while allowing your tests to run serially, allowing for flexible and accurate reporting.
With Mocha, you have many rich features built into the framework, such as browser support, asynchronous and parallel testing, test coverage testing, JavaScript API for running tests, node native ES modules support, etc. These features allow the development team to have one testing framework to support various needs.
According to GitHub, some of the growth statistics of the Mocha library as of the time of writing include more than 22.1k GitHub Stars and about 2m GitHub Usage, making Mocha a very popular testing framework.
You can explore all the features supported by the Mocha unit testing framework right out of the box from the official Mocha documentation.
While Mocha is a great testing framework, some specific reasons and features make Mocha a popular choice for both Test Driven Development (TDD) and Behaviour Driven Development (BDD) development teams.
Note : Run your Mocha tests across 3000+ real browsers. Try LambdaTest Now!
Mocha unit testing framework is widely used for both TDD and BDD teams because of the rich features introduced into Mocha right out of the box. Some reasons why Mocha is a popular choice are listed below:
Mocha, as a testing framework, has more features and benefits included inside the framework that we can mention here. However, it has certain limitations as well.
As with every technology, there are always disadvantages and limitations to using a particular technology. In this section of the Mocha unit testing tutorial, we will explore the limitation of using the Mocha unit testing framework.
Above are some of the known limitations of the Mocha unit testing framework. Also, note that some development teams may find these limitations an advantage. So it depends on what your team looks for in a testing framework.
In the next section of the Mocha unit testing tutorial, we will learn how to run your first Mocha unit test in JavaScript and gain useful knowledge on how to set it up in your JavaScript project.
This section will explore the basic elements of Mocha unit testing, such as suites, specs, and many others listed below.
To begin, create a demo project that will help us to practically learn and understand the different elements used in Mocha unit testing.
After that, create a project folder in your preferred location and execute the following command to initialize a new project's package.json file.
npm init -y
Next, create an `helpers.js` file and add the following code:
function fibonacci(num, memo) {
memo = memo || {};
if (memo[num]) return memo[num];
if (num <= 1) return 1;
return (memo[num] = fibonacci(num - 1, memo) + fibonacci(num - 2, memo));
}
module.exports = {
fibonacci: Fibonacci,
};
The above code snippet is a simple Fibonacci series computation. We will use this example to understand the different elements of Mocha unit testing.
A suite refers to a collection of specifications or test cases, which are used to test a set of functionalities or behaviors in JavaScript code. Typically, a suite is encapsulated within an object/class or a function. You can define a suite of test cases with the help of `describe` block.
The `describe` block requires two essential parameters: a string specifying the suite name and a function that implements the actual code of the test suite.
Let's explore an example of our first Mocha test suite:
describe('Test Helpers', function () {
/**
* Add all your related test cases here
*
*/
});
A spec is a declaration of a specific test that belongs to a test suite. This declaration is made by utilizing the Mocha global function `it()`, which requires two parameters: the title of the spec and a function that implements the actual test case.
It can contain one or more expectations, which are used to determine the correctness of the test. Each expectation is essentially an assertion that can return either true or false. If an expectation returns true, the spec is passed. However, if the expectation returns false, the spec fails.
Here is how to declare a spec in Mocha:
describe('Test Helpers', function () {
it('should calculate Fibonacci series', function () {
/*...*/
});
});
Mocha provides hooks that should be used to set up preconditions and clean up after your tests. They are the before, after, beforeEach, and afterEach functions.
For instance, if you need initial variables to use in each of your test suites, you can simply add the initialization process inside the `beforeEach` function, which will be initialized on every test case. Also, you can reset any variable of your choice using the `afterEach` function.
describe('using hooks', function () {
before(function () {
// runs once before the first test in this block
});
after(function () {
// runs once after the last test in this block
});
beforeEach(function () {
// runs before each test in this block
});
afterEach(function () {
// runs after each test in this block
});
// test cases
it('should calculate Fibonacci series', function () {
const fib = fibonacci(4);
expect(fib).toEqual(5);
});
});
Mocha allows asynchronous test suites. It allows the use of callbacks, async/await, and promises. Below we are going to show how to write asynchronous test cases.
describe('Test Helpers', function () {
it('should calculate Fibonacci series', function (done) {
var fib = new fibonacci(4);
fib.calculate(function (err) {
if (err) done(err);
else done();
});
});
});
Next, let's demonstrate how to use async/await when writing our test cases.
describe('Test Helpers', function () {
it('should calculate Fibonacci series', async function () {
const fib = new fibonacci(4);
const result = await fib.calculate();
expect(result).toEqual(5);
});
});
Mocha also allows the use of arrow functions in writing test cases, as shown in the code snippet below:
describe('Test Helpers', () => {
it('should calculate Fibonacci series', () => {
const fib = new fibonacci(4);
expect(fib).toEqual(5);
});
});
These are test cases that will be written later. Test results will include pending tests and be marked as pending. Tests that are pending are not considered failed tests. These test cases do not have any callbacks or matchers.
describe('Test Helpers', function () {
// pending test below
it('should calculate Fibonacci series');
});
Using the exclusivity feature, you can only run a specific suite. You can specify the test you want to run in a test suite by using the only function as shown below:
describe('Test Helpers', function () {
it.only('should return -1 unless present', function () {
// ...
});
it('should return the index when present', function () {
// ...
});
});
Only the test cases with the only function will be executed.
Mocha allows you to ignore a test case by appending the skip function to the test case. Let's demonstrate it as shown below:
describe('Test Helpers', function () {
it.skip('should return -1 unless present', function () {
// this test will not be run
});
it('should return the index when present', function () {
// this test will be run
});
});
Mocha allows you to retry failed tests up to a certain number of times. This feature is designed to handle end-to-end tests (functional tests/Selenium) where resources cannot be easily mocked/stubbed.
Let's look at examples of how to implement it below:
describe('retries', function () {
// Retry all tests in this suite up to 4 times
this.retries(4);
beforeEach(function () {
browser.get('https://www.lambdatest.com/');
});
it('should succeed on the 3rd try', function () {
// Specify this test to only retry up to 2 times
this.retries(2);
expect($('.foo').isDisplayed()).to.eventually.be.true;
});
});
In the next section, we will explore how to set up the Mocha unit testing environment and configure Mocha to work with our demo project setup.
Note : Automate Mocha unit testing on the cloud. Try LambdaTest Now!
Writing a unit test is simpler than you think using Mocha unit testing frameworks. In the example, we will use the Mocha framework to write some basic test cases.
Subscribe to the LambdaTest YouTube Channel to get the latest tutorials around Selenium testing, Cypress testing, and more.
We will write some unit test cases to sum up numbers on the LambdaTest Playground website using Selenium.
First, clone the Mocha testing repository from GitHub, and add the following libraries to our package.json file.
npm install mocha assert
Before the tests are run, please set the following environment variables in your .env file. You can find the LambdaTest username and access key on your LambdaTest Profile page.
For macOS:
LT_USERNAME=
LT_ACCESS_KEY=
GRID_HOST=hub.lambdatest.com/wd/hub
After installing the libraries and setting the environment variables, below is the implementation of the web calculator:
const { Builder, By } = require('selenium-webdriver');
let driver;
const USERNAME = process.env.LT_USERNAME ?? '';
const KEY = process.env.LT_ACCESS_KEY ?? '';
const GRID_HOST = 'hub.lambdatest.com/wd/hub';
// Setting LambdaTest Capabilities
const searchCapabilities = {
browserName: 'Chrome',
browserVersion: '107.0',
'LT:Options': {
username: USERNAME,
accessKey: KEY,
geoLocation: 'US',
platformName: 'Windows 10',
build: 'calculate',
project: 'Calculate',
w3c: true,
plugin: 'node_js-node_js',
},
};
const searchGridUrl = 'https://' + USERNAME + ':' + KEY + '@' + GRID_HOST;
// Create a calculate function with LamdaTest
async function calculateWithLambdaTest(num1 = 5, num2 = 5) {
try {
driver = await new Builder()
.usingServer(searchGridUrl)
.withCapabilities(searchCapabilities)
.build();
await driver.get(
'https://www.lambdatest.com/selenium-playground/simple-form-demo'
);
const inputSum1 = await driver.findElement(By.id('sum1'));
const inputSum2 = await driver.findElement(By.id('sum2'));
const button = await driver.findElement(
By.xpath(
'//button[.='Get values']'
)
);
inputSum1.sendKeys(num1);
inputSum2.sendKeys(num2);
button.click();
const result = await driver.findElement(By.id('addmessage'));
return await result.getText();
} catch (error) {
throw new Error(error);
} finally {
await driver.quit();
}
}
module.exports = {
calculate: calculateWithLambdaTest,
};
Let’s walk through the code together and understand the nitty-gritty of it.
Step 1: Add required packages and create Selenium capabilities.
First, we need the selenium-webdriver packages. Before running the operation, please set the following environment variables in your .env file. You can find the username and access key on your LambdaTest Profile page.
Next, generate your Selenium configuration using the LambdaTest Capabilities Generator. LambdaTest Capabilities Generator . Set your necessary configuration and copy the JavaScript object to your code, as shown below.
Next, we created a driver using the configuration and capacity before performing the calculation with the LambdaTest grid using the 'calculateWithLambdaTest()' function.
Step 2: Performing the Operation.
First, we create an instance of the driver using the configurations above. Next, we open the webpage where the calculator is located using the 'driver.get()' function. Lastly, we find elements on the page using Selenium `findElement` function.
Furthermore, still inside the ''calculateWithLambdaTest”' function, we used the 'sendKeys()' function to pass number input to the input element we retrieved using the `findElement` function as shown below:
Lastly, we used the 'click()' function to submit the form and perform the calculation. To get the result of the calculation, we use the 'findElement(By.id('addmessage'))' to retrieve the result and the 'getText()' function to retrieve the text value of the result element.
We create a simple Express server to test out the implementation manually before running the test using the Mocha unit testing framework.
First, install ExpressJS using the command below:
npm install express
Here is the output of the command:
Lastly, we created a server.js file in the root directory and added the following code snippet to create a simple Express server.
const express = require('express');
const Calculator = require('./calculate');
const app = express();
const port = 3002;
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.get('/calculate', async (request, response) => {
try {
const num1 = request.query?.num1 ?? 4;
const num2 = request.query?.num2 ?? 6;
const data = await Calculator.calculate(num1, num2);
console.log(num1, num2, data);
response.status(200).json(data);
} catch (error) {
response.status(500).json({
message: 'Server error occurred',
});
}
});
app.listen(port, () => {
console.log( 'Example app listening at http://localhost:${port}');
});
In the next section, we're going to explore how to test the Node.js applications using Mocha and ExpressJS.
Lastly, open the tests/calculate.test.js file inside the repository to explore how to write real-world unit tests with the Mocha and Assert JavaScript framework.
Here is the code snippet:
const assert = require('assert');
const request = require('request');
let url;
beforeEach(async () => {
url = 'http://localhost:3002/calculate';
});
describe('Search', () => {
it('calculate the sum of two values', async () => {
request(url, function (error, response, body) {
assert.equal(response.statusCode, 200);
assert.equal(body[0], 9);
done();
});
});
it('calculate the wrong sum of two values', async () => {
request(url + '?num1=5&num2=6', function (error, response, body) {
assert.equal(response.statusCode, 200);
assert.not.equal(body[0], 9);
done();
});
});
});
Lastly, we included all the other test cases inside the Describe block, each test case tests a particular behavior or implementation of a feature.
To run your test, type the following command into your root terminal.
npm start
npm run test
After successfully performing running the test, you should be greeted with green passes for your test, like the screenshot below:
Until now, we have manually run the test with the command above to ensure that the test is passing before we go ahead with deployment.
We can also automate this process by leveraging the LambdaTest cloud grid, enabling the implementation of a test strategy during deployment.
LambdaTest is a digital experience testing platform that lets you perform manual and automation testing for web and mobile apps across 3000+ real browsers, devices, and operating system combinations.
With LambdaTest, you can run Mocha unit tests in parallel on a cloud-based grid, thereby accelerating your test execution cycles by multiple times. If you are looking to get started with automation testing using Mocha on LambdaTest, check our support documentation on Mocha testing with Selenium.
Software testing is a way to ensure that the software under test (SUT) conforms with the requirements during or after development. It is a very important aspect of software engineering as it reduces bugs and deployment of defective software products.
Mocha is one such tool, and it's a flexible JavaScript testing framework that makes testing simple and more flexible.
In this Mocha JavaScript tutorial, we learned why to use the Mocha framework and the different limitations of using Mocha. Lastly, we examined how to test a demo Node.js application with the Mocha unit testing framework.
Delve into our top Unit Testing Interview Questions guide, designed to help you excel in unit testing interviews. It covers a wide range of topics, from syntax to advanced techniques, with detailed solutions.
Reviewer's Profile
Himanshu Sheth
Himanshu Sheth is a seasoned technologist and blogger with more than 15+ years of diverse working experience. He currently works as the 'Lead Developer Evangelist' and 'Senior Manager [Technical Content Marketing]' at LambdaTest. He is very active with the startup community in Bengaluru (and down South) and loves interacting with passionate founders on his personal blog (which he has been maintaining since last 15+ years).
Get 100 minutes of automation test minutes FREE!!