Table of Contents
Introduction to backend testing
Backend Testing is used to check server-side API calls. With the help of backend testing, we can assure that failure of the database, or one can say defects of the database are not affected in our application.
Why Backend Testing is required?
There are following the important aspects which are taken into consideration
- With the help of backend testing, you can find many bugs without running actual API calls or the application.
- With backend testing, you can check how long it’ll take to retrieve data from the database and how to make your application more efficient.
- Backend testing checks at the application layer and database layer can provide a crash-free environment for our application.
Prerequisites:
- Node (Recommended 12.19.0): You’ll need to have Node >= 8.10 and npm >= 5.6 on your machine.
- angular/cli (Recommended 11.1.4)
- Express (Recommended 4.17.1)
Alternatives for mocha
Node.js has many testing and assertion tools like Jest, lab & code, ava, and Mocha.
So why not other than mocha? Let’s briefly introduce others and get a deep understanding of mocha, Sinon, and chai.
Jest
Jest is used to test the front end and then expanded with backend testing functionalities. Jest provides built-in libraries for assertion and also has support for almost any js project. jest also supports parallel execution for test suites.
- parallel processing for test cases makes debugging for tests very difficult. And
- With this drawback, error tracking for test cases is very difficult, making it hard to update test cases for success.
Lab
The lab is a test runner for backend testing. It provides a TDD approach for running test cases. However,
- The lab does not provide any global functionality to improve our testing.
- You have to import lab and code dependencies for every test suite you write.
Ava
Ava is a test runner same as a lab but with some advancements. Ava uses parallel testing like jest.
- Ava runs tests parallelly so sharing variables across test suites is difficult and risky.
- Ava does not allow you to run group tests.
What is mocha
Mocha is a more powerful tool for testing both TDD and BDD approaches. Mocha provides easy and simple syntax. It has wasp support for any assertion libraries. Mocha has also support for hooks, async hooks.
Mocha is a testing framework that provides you simplicity for asynchronous testing. Which helps us to run tests with accurate reporting and flexibility for writing tests.
Mocha provides us best-testing frameworks and it has support for wasp amount of libraries for the Sinon an assertion, & mocking, and spying. Mocha uses life cycle hooks to provide a better testing environment with fewer lines of code.
Let’s see some of Mocha’s features.
- Provides simple async support including promises.
- Provides async test timeout support which helps to run our test cases in parallel mode.
- Comes with an auto-exit function to prevent hanging from the active loop.
- Provides necessary hooks like before, before each, after, after each.
- Use any assertion library you want
What is chai
Chai is an assertion library that is suggested by Mocha itself for assertion. It helps to compare the output of certain tests with their expected value. Chai helps us with its syntax that you can almost read it like English. Chai provides three assertion interfaces: expect(), assert() and should(). We can use any of these interfaces for assertions.
What is Sinon
In our application, our components are always interconnected. So when we are testing one component we need results from another component so that functionality in testing is provided by stub spy and mock methods of Sinon. Stub, Spy, and Mock are used to make work easier with complicated functions of the system.
- Spy
Spy is mostly used to know what function is called and how many arguments and results that function returns.
- Stub
A stub is similar to spy but its behavior is predefined. A stub is also able to call any function automatically that is meant to be called. I.e.
We can use a stub to:
- Get predefined results for a function like exception or success.
- Set response we want according to data.
- Prevent a specific method call directly (mostly HTTP request).
- We can restore its original behavior easily
- Mock
Mock can be a fake function like a spy and also along with that it can be pre-programmed behavior and pre-programmed expectations. Mock can do work of both functionalities stub and spy, so why don’t we use mock every time,
Well when you are not adding any specific outcome on a method then you must use stub instead of mock, with mock we can end up making conditions more specific than needed and it is hard to understand the test case and easy to break the test.
Backend Testing Example with mocha, chai, and Sinon
Let’s create test cases to understand how mocha, chai, and Sinon work in real-time applications. For this example, there is a backend application created with crud operations for a wish list. Now, we can start with installing tools
Step-1: Install mocha chai and Sinon
Now, let’s work on the testing part.
First, you have to install mocha, chai & Sinon. Run the following command to install
npm i --save-dev mocha
After running this command npm will install mocha and add dev-dependencies in your application.
Do the same for Sinon and chai.
npm i --save-dev chai
npm i --save-dev sinon
Start with a simple test to understand the syntax.
Step-2: Write a simple test
There is a method(simpleTest) in the app.component file which returns a string. write a test case to check this function’s outcome.src/app/app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
simpleTest = () => {
return 'Simple Test';
}
}
.src/app/app.component.spec.ts
import { AppComponent } from './app.component';
import * as chai from 'chai';
const expect = chai.expect;
describe('AppComponent Test cases', () => {
it('should run simple test for addnumber function :- ', () => {
const myComponent = new AppComponent();
expect(myComponent.simpleTest()).to.be.equal('Simple Test');
});
});
Update package.json with the script given below.
"scripts": {
"Build": "tsc",
"test": " npm run build | mocha './dist/out-tsc/src/app/*.spec.js'",
}
Run this test file with npm run test you will see that your test will run successfully.
While running the test, if you get any error regarding chai & Sinon fire these two commands in your terminal and run your test again.
npm i --save-dev @types/sinon
npm i --save-dev @types/chai
After getting success, let’s test some functions from the node app.
Step-3: Create a test file and build a test environment.
Create file wish.controller.spec.ts or update file created for testing purposes. wish.controller.ts will contain a method for service calls.
export const getWishHandler = async (req: Request, res: Response) => { const Wish: any = getWish(); if (Wish) { return res.status(200).json({ status: 200, message: 'Wishes got successfully', wish: Wish });
} else { return res.status(404).json({ status: 404, message: 'no data found', wish: Wish }) } };
Add import statements for Chai and Sinon to start with your testing environment.
import * as chai from 'chai';
const expect = chai.expect;
const sinon = require('sinon');
Also, import the methods you want to write test cases for.
import { getWishHandler } from './wish.controller';
Start with describe and pass name to it. Mocha allows you to add multiple describe inside one describe.
xdescribe('AppComponent Test cases', () => { describe('It should stub function :-', () => { before(() => { wishs: [ { _id: '1', title: 'wish 1', }, { _id: '2', title: 'wish 2', } ], }); after(() => { sinon.restore(); }); It('should get All Wishes', async function () { const req: any = {}; const find = sinon.stub(Wish, 'find').returns(wishs); await getWishHandler(req, res); expect(find.status).to.equal(200); expect(find.calledOnce).to.be.true; }); }); } describe('wish Controller Test cases should return 404', () => { let status; let json: any; let res: any; beforeEach(async () => { status = sinon.stub(); json = sinon.spy(); res = { json, status }; status.returns(res); }); describe('It should stub function :-', () => {
after(() => { sinon.restore(); }); it('should get All Wishes', async function() { const req: any = {}; let find = sinon.stub(Wish, 'find').returns(null); await getWishHandler(req, res); expect(json.args[0][0].status).to.equal(404); expect(find.calledOnce).to.be.true; });
}); });
Step-4: Run test case and get results
Run this test case with the npm run test command.
Step-5: Use advanced features to make development easier.
- Mocha provides xdescribe, xit to skip that test cases for development purposes.
- Mocha provides detailed logs for errors to make your error tracking easier.
- Use test duration to improve your code efficiency.
- You can use command-line options with mocha to get more information about tests
Advantages
- You can take both BDD or TDD approaches as your need.
- Mocha supports any of assertion libraries
- Mocha make asynchronous testing way simpler
- Its syntax is simple and error tracking is much better.
- Mocha is compatible with almost every web browser available in the market.
Disadvantages
- Mocha requires a good amount of configurations.
- Mocha uses an explicit assertion library.
- Work with snapshot testing is much harder
Conclusion
So far, till now we have covered mocha’s exclusive features to test our functionalities. Combining mocha with chai and Sinon will give us lots of flexibility and functionalities to work with. Mocha is one of the best tools for backend testing.
Ready to enhance your testing game? With mocha, chai, and Sinon, writing test cases is very easy. Mocha also has big community support to get help. Take the next step in improving your testing strategy — Contact us and let's elevate your testing experience together.