0% found this document useful (0 votes)
8 views10 pages

Se2 Exp7

The document outlines an experiment on unit testing and code coverage in software engineering, detailing the theory behind unit testing, its importance, and the use of Mocha, Chai, and NYC for testing and coverage analysis. It includes a comprehensive code example demonstrating various test cases for a card controller, including listing, retrieving, updating, and deleting properties. The results of the testing, including code coverage statistics, are also presented, highlighting the effectiveness of the tests performed.

Uploaded by

dmsuhagiyab22
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views10 pages

Se2 Exp7

The document outlines an experiment on unit testing and code coverage in software engineering, detailing the theory behind unit testing, its importance, and the use of Mocha, Chai, and NYC for testing and coverage analysis. It includes a comprehensive code example demonstrating various test cases for a card controller, including listing, retrieving, updating, and deleting properties. The results of the testing, including code coverage statistics, are also presented, highlighting the effectiveness of the tests performed.

Uploaded by

dmsuhagiyab22
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 10

Software Engineering 2 Lab – Experiment 7

Name: Denish Suhagiya​ Date: 10th April 2025


Reg ID: 221070071
Batch: C
Faculty: Mr. Shreekant Bedekar

Aim: To perform unit testing and code coverage.

Theory:
​ Unit testing is a software testing technique where individual units or

components of a software are tested independently to ensure they


perform as expected. The main goal of unit testing is to validate each
unit's functionality in isolation, typically through automated testing. This
helps identify defects early in the development cycle, making it easier and
cheaper to fix them.

​ Unit testing involves writing test cases for each unit of code to verify its

behavior against expected outcomes. These test cases are usually small
and focused, targeting specific functionalities or scenarios. By testing
units in isolation, developers can easily pinpoint and fix any bugs or
issues, without needing to navigate through the entire codebase.

​ Code coverage is a metric used to measure the extent to which source

code is executed by a test suite. It provides insight into the effectiveness


of testing by showing which parts of the code are exercised during testing
and which parts remain untested. Code coverage tools analyze the
relationship between executed code and the corresponding test cases,
highlighting areas that require additional testing.

​ Mocha and Chai are popular JavaScript testing frameworks used for

writing and running unit tests. Mocha provides a flexible and feature-
rich test runner that supports various testing styles (e.g., BDD, TDD) and
asynchronous testing. Chai, on the other hand, is an assertion library that
works seamlessly with Mocha and provides expressive and readable
assertions, making test cases easier to write and understand.

​ NYC (or Istanbul) is a code coverage tool for JavaScript that works well

with Mocha and Chai. It instruments JavaScript code to track which


parts are executed during testing and generates reports showing code
coverage statistics. NYC helps developers assess the effectiveness of
their test suites and identify areas of code that require additional
testing.

Code (app_test.js file):


const chai = require("chai");
const sinon = require("sinon");
const mongoose = require("mongoose");
const { expect } = chai;

const Cardmodel = require("../../models/cardModel");


// Import the app instead of server
const app = require("../../server");
// Use supertest
const request = require("supertest");

describe("Card Controller Tests", function () {


// Create sample data
const sampleCard = {
_id: "507f1f77bcf86cd799439011",
name: "Test Property",
location: "Test Location",
area: "1200 sqft",
star: "4",
tag: ["modern", "luxury"],
price: "1500000",
description: "Beautiful test property with great amenities",
img: {
img1: "https://example.com/image1.jpg",
img2: "https://example.com/image2.jpg",
},
};

// Create a mongoose ObjectId from the sample property ID


const validObjectId = new mongoose.Types.ObjectId(sampleCard._id);
// Mock data for tests
const mockProperties = Array(15)
.fill()
.map((_, i) => ({
...sampleCard,
_id: new mongoose.Types.ObjectId(),
name: `Test Property ${i + 1}`,
}));

// Setup stubs for Mongoose methods


let findStub,
findByIdStub,
createStub,
findOneAndUpdateStub,
findOneAndDeleteStub;

beforeEach(() => {
// Create stubs for all Mongoose methods used in the controller
findStub = sinon.stub(Cardmodel, "find");
findByIdStub = sinon.stub(Cardmodel, "findById");
createStub = sinon.stub(Cardmodel, "create");
findOneAndUpdateStub = sinon.stub(Cardmodel, "findOneAndUpdate");
findOneAndDeleteStub = sinon.stub(Cardmodel, "findOneAndDelete");

// Setup the find stub with pagination


findStub.returns({
limit: sinon.stub().returns(mockProperties.slice(0, 12)),
});
});

afterEach(() => {
// Restore all stubs
sinon.restore();
});

// Test 1: Listing all properties (getCards)


describe("GET / - List all properties", () => {
it("should get all properties with a limit of 12", async () => {
const res = await request(app).get("/");

expect(res.status).to.equal(200);
expect(res.body).to.be.an("array");
expect(res.body.length).to.be.at.most(12); // Check limit is
working
expect(findStub.calledOnce).to.be.true;
});
it("should handle database errors when listing properties", async
() => {
// Override the stub to throw an error
findStub.restore();
findStub = sinon
.stub(Cardmodel, "find")
.throws(new Error("Database connection error"));

const res = await request(app).get("/");

expect(res.status).to.equal(500);
expect(res.body).to.have.property("error");
});
});

// Test 2: Getting a single property (getCard)


describe("GET /:id - Get single property", () => {
it("should get a single property by valid ID", async () => {
// Setup the stub to return our sample property
findByIdStub.withArgs(sinon.match.any).resolves(sampleCard);

const res = await request(app).get(`/${sampleCard._id}`);

expect(res.status).to.equal(200);
expect(res.body).to.be.an("object");
expect(res.body).to.have.property("name", sampleCard.name);
});

it("should return 404 for invalid MongoDB ID format", async () => {


const res = await request(app).get("/invalid-id-format");

expect(res.status).to.equal(404);
expect(res.body).to.have.property("error", "No Such Card
Exists");
});

it("should return 404 for non-existent ID", async () => {


// Valid ID format but no property found
const nonExistentId = new mongoose.Types.ObjectId();
findByIdStub.withArgs(sinon.match.any).resolves(null);

const res = await request(app).get(`/${nonExistentId}`);

expect(res.status).to.equal(404);
expect(res.body).to.have.property("error", "No such Cards
exists");
});
describe("PATCH /:id - Update a property", () => {
it("should update a property with valid ID and data", async () => {
const updateData = {
price: "1600000",
description: "Updated description for test property",
};

const updatedProperty = {
...sampleCard,
...updateData,
};

findOneAndUpdateStub.resolves(updatedProperty);

const res = await request(app)


.patch(`/${sampleCard._id}`)
.send(updateData);

expect(res.status).to.equal(200);
expect(res.body).to.be.an("object");
expect(res.body).to.have.property("price", updateData.price);
expect(res.body).to.have.property("description",
updateData.description);
});

it("should return 404 for invalid MongoDB ID format", async () => {


const res = await request(app)
.patch("/invalid-id-format")
.send({ price: "1600000" });

expect(res.status).to.equal(404);
expect(res.body).to.have.property("error", "No Such Card
Exists");
});

it("should return 404 for non-existent ID", async () => {


// Valid ID format but no property found
const nonExistentId = new mongoose.Types.ObjectId();
findOneAndUpdateStub.resolves(null);

const res = await request(app)


.patch(`/${nonExistentId}`)
.send({ price: "1600000" });

expect(res.status).to.equal(404);
expect(res.body).to.have.property("error", "No such Cards
exists");
});

it("should handle database errors when updating a property", async


() => {
findOneAndUpdateStub.restore();
findOneAndUpdateStub = sinon
.stub(Cardmodel, "findOneAndUpdate")
.throws(new Error("Database error"));

const res = await request(app)


.patch(`/${sampleCard._id}`)
.send({ price: "1600000" });

expect(res.status).to.equal(500);
expect(res.body).to.have.property("error");
});
});

// Test 5: Deleting a property (deleteCard)


describe("DELETE /:id - Delete a property", () => {
it("should delete a property with valid ID", async () => {
findOneAndDeleteStub.resolves(sampleCard);

const res = await request(app).delete(`/${sampleCard._id}`);

expect(res.status).to.equal(200);
expect(res.body).to.be.an("object");
expect(res.body).to.have.property("_id", sampleCard._id);
});

it("should return 404 for invalid MongoDB ID format", async () => {


const res = await request(app).delete("/invalid-id-format");

expect(res.status).to.equal(404);
expect(res.body).to.have.property("error", "No Such Card
Exists");
});

it("should return 404 for non-existent ID", async () => {


// Valid ID format but no property found
const nonExistentId = new mongoose.Types.ObjectId();
findOneAndDeleteStub.resolves(null);

const res = await request(app).delete(`/${nonExistentId}`);

expect(res.status).to.equal(404);
expect(res.body).to.have.property("error", "No such Cards
exists");
});

it("should handle database errors when deleting a property", async


() => {
findOneAndDeleteStub.restore();
findOneAndDeleteStub = sinon
.stub(Cardmodel, "findOneAndDelete")
.throws(new Error("Database error"));

const res = await request(app).delete(`/${sampleCard._id}`);

expect(res.status).to.equal(500);
expect(res.body).to.have.property("error");
});
});

// Test controller functions directly for better coverage


describe("Direct controller function tests", () => {
it("should handle getCards function directly", async () => {
const req = {};
const res = {
status: function (code) {
this.statusCode = code;
return this;
},
json: function (data) {
this.body = data;
return this;
},
};

await getCards(req, res);


expect(res.statusCode).to.equal(200);
expect(res.body).to.be.an("array");
});
});
});
Output:
1.​ Testing using Mocha chai:
2.​Testing using NYC:
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s ​
-----------------|---------|----------|---------|---------|-------------------​
All files | 85.73 | 81.24 | 88.46 | 85.73 | ​
controllers/ | 91.35 | 87.50 | 90.00 | 91.35 | ​
cardController | 93.42 | 91.67 | 100.00 | 93.42 | 58-59,69 ​
models/ | 82.86 | 75.00 | 87.50 | 82.86 | ​
cardModel.js | 82.86 | 75.00 | 87.50 | 82.86 | 51-54,79-82 ​
routes/ | 100 | 100 | 100 | 100 |

Conclusion: Thus, we understood the principles of unit testing and


code coverage. Also, we performed them using Mocha-Chai and NYC.

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy