Backend testing ensures that APIs, database interactions, and business logic work as expected. Mocha and Chai are two popular JavaScript testing frameworks used to write and execute backend tests in Node.js.
In this guide, we’ll cover:
- Introduction to Mocha and Chai
- Setting up Mocha and Chai in a Node.js project
- Writing unit tests using Mocha and Chai
- Testing APIs with Supertest
- Best practices for backend testing
1. Introduction to Mocha and Chai
Mocha
Mocha is a feature-rich JavaScript testing framework that runs on Node.js and supports both synchronous and asynchronous testing.
✔️ Supports hooks (before
, beforeEach
, after
, afterEach
)
✔️ Works well with assertion libraries like Chai
✔️ Allows writing both unit and integration tests
Chai
Chai is an assertion library that provides multiple styles of writing tests:
- Assert (Node.js native style)
- Expect (Readable syntax)
- Should (Chainable BDD style)
2. Setting Up Mocha and Chai in Node.js
Step 1: Initialize a Node.js Project
Run the following command:
shCopyEditmkdir mocha-chai-testing && cd mocha-chai-testing
npm init -y
Step 2: Install Mocha and Chai
shCopyEditnpm install --save-dev mocha chai
Step 3: Update package.json
Modify the scripts
section:
jsonCopyEdit"scripts": {
"test": "mocha"
}
Now, you can run tests using npm test
.
3. Writing Unit Tests Using Mocha and Chai
Let’s create a simple function to test:
Create math.js
javascriptCopyEditfunction add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
module.exports = { add, subtract };
Create a Test File test/math.test.js
javascriptCopyEditconst { expect } = require("chai");
const { add, subtract } = require("../math");
describe("Math Functions", () => {
it("should return the sum of two numbers", () => {
expect(add(2, 3)).to.equal(5);
});
it("should return the difference of two numbers", () => {
expect(subtract(5, 3)).to.equal(2);
});
it("should return a negative number when subtracting larger from smaller", () => {
expect(subtract(3, 5)).to.equal(-2);
});
});
Run the Tests
shCopyEditnpm test
✅ If everything is correct, Mocha will show passing tests.
4. Testing APIs with Mocha, Chai, and Supertest
When testing REST APIs, we use Supertest, an HTTP assertion library.
Step 1: Install Supertest
shCopyEditnpm install --save-dev supertest
Step 2: Create a Basic Express API (server.js
)
javascriptCopyEditconst express = require("express");
const app = express();
app.use(express.json());
app.get("/api/hello", (req, res) => {
res.json({ message: "Hello, World!" });
});
app.post("/api/user", (req, res) => {
const { name } = req.body;
res.json({ message: `User ${name} created` });
});
module.exports = app;
Step 3: Create a Test File (test/api.test.js
)
javascriptCopyEditconst request = require("supertest");
const { expect } = require("chai");
const app = require("../server");
describe("API Endpoints", () => {
it("should return a hello message", async () => {
const res = await request(app).get("/api/hello");
expect(res.status).to.equal(200);
expect(res.body.message).to.equal("Hello, World!");
});
it("should create a new user", async () => {
const res = await request(app).post("/api/user").send({ name: "Vikram" });
expect(res.status).to.equal(200);
expect(res.body.message).to.equal("User Vikram created");
});
});
Run API Tests
shCopyEditnpm test
✅ If the API is correct, all tests should pass.
5. Using Hooks for Setup and Cleanup
Mocha provides hooks (before
, beforeEach
, after
, afterEach
) to set up preconditions or clean up after tests.
Example:
javascriptCopyEditdescribe("User Tests", () => {
before(() => {
console.log("Before all tests – Setup DB connection");
});
after(() => {
console.log("After all tests – Cleanup DB connection");
});
beforeEach(() => {
console.log("Before each test – Reset test data");
});
afterEach(() => {
console.log("After each test – Cleanup");
});
it("should create a user", () => {
expect(true).to.be.true;
});
});
6. Best Practices for Backend Testing
Best Practice | Why It Matters? |
---|---|
Write independent tests | Avoid dependencies between test cases. |
Mock external services | Prevent reliance on third-party APIs. |
Use descriptive test names | Improves readability and debugging. |
Automate tests in CI/CD | Ensures code stability. |
Cover edge cases | Test with invalid inputs and large data sets. |
7. Running Tests in a CI/CD Pipeline (GitHub Actions)
To automate tests, create a GitHub Actions workflow:
Create .github/workflows/test.yml
yamlCopyEditname: Node.js CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test
Now, every time you push code, tests run automatically! 🚀
8. Summary & Conclusion
Mocha and Chai are powerful tools for backend testing in Node.js. By using them, developers can write clear, maintainable, and effective tests for both unit and API endpoints.
Key Takeaways
✔️ Mocha provides a structured testing framework.
✔️ Chai offers flexible assertion styles (expect
, should
, assert
).
✔️ Supertest simplifies API testing.
✔️ CI/CD pipelines automate test execution.