Tuesday, 28 January 2025

Lecture Notes Of Class 22: Unit Testing with Mocha and Chai

 

Lecture Notes Of Class 22: Unit Testing with Mocha and Chai

Objective:

By the end of this class, you should understand unit testing and how to write tests for individual components of your code using Mocha and Chai.


What is Unit Testing?

Unit testing is the practice of testing individual units or components of a program in isolation. The purpose of unit testing is to ensure that each part of your program works as expected. This is a critical part of the software development process because it helps identify and fix bugs early on, improving the overall quality and reliability of your code.


Why Unit Testing?

1.  Early Bug Detection: Catch bugs early during development.

2.  Refactoring Confidence: When you change or refactor code, unit tests ensure that everything still works.

3.  Documentation: Well-written unit tests can serve as documentation for your code's behavior.

4.  Improved Design: Writing tests forces you to think about the design of your code, leading to cleaner, more modular, and testable code.


Tools for Unit Testing in Node.js

  • Mocha: A testing framework for Node.js that provides functions like describe, it, and beforeEach to organize your tests.
  • Chai: An assertion library that works with Mocha to validate the expected output of your code. It provides assertions like should, expect, and assert to check if the output matches the expected value.

Mocha: The Testing Framework

Mocha helps organize your tests in a structured manner. You define test cases using the following methods:

  • describe(): A function that groups related tests together.
  • it(): A function that defines a single test case.
  • beforeEach() and afterEach(): Functions that run before or after each test, useful for setting up or cleaning up test data.
  • before() and after(): Functions that run once before or after all tests, typically used for global setup/teardown.

Chai: The Assertion Library

Chai provides different styles of assertions, and the most commonly used ones are:

  • expect(): A BDD-style assertion.
  • assert(): An assertion that works in an assertion-based style.
  • should(): An extension of the expect style that adds should-like syntax to objects.

Example:

js
const expect = require('chai').expect;
 
expect(4).to.equal(4); // This will pass
expect(4).to.equal(5); // This will fail

Example Code: Setting Up Mocha and Chai

1.  Install Mocha and Chai

To start using Mocha and Chai, you'll need to install them in your Node.js project.

bash
npm install --save-dev mocha chai

2.  Create a Test File

You can create a test folder in your project and add test files inside it. For example, create a file called mathTest.js.

js
const expect = require('chai').expect;
const add = (a, b) => a + b;
 
describe('Math Functions', function() {
  describe('add()', function() {
    it('should return the sum of two numbers', function() {
      const result = add(2, 3);
      expect(result).to.equal(5);
    });
  });
});

3.  Running Tests

Add a test script to your package.json to run Mocha:

json
"scripts": {
  "test": "mocha"
}

Now, you can run the tests using the command:

bash
npm test

Lab Tasks:

1. Write Tests for Different Functions

Let's consider a simple calculator module that has three functions: add(), subtract(), and multiply().

First, define the functions you want to test:

js
// calculator.js
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;
const multiply = (a, b) => a * b;
 
module.exports = { add, subtract, multiply };

Now, write unit tests for these functions.

js
// test/calculatorTest.js
const expect = require('chai').expect;
const calculator = require('../calculator');
 
describe('Calculator', function() {
  describe('add()', function() {
    it('should return the sum of two numbers', function() {
      expect(calculator.add(2, 3)).to.equal(5);
    });
  });
 
  describe('subtract()', function() {
    it('should return the difference of two numbers', function() {
      expect(calculator.subtract(5, 3)).to.equal(2);
    });
  });
 
  describe('multiply()', function() {
    it('should return the product of two numbers', function() {
      expect(calculator.multiply(2, 3)).to.equal(6);
    });
  });
});

2. Use Assertions from Chai to Validate the Output

In the test cases above, we've used expect() to check if the actual output of the function matches the expected output. Some other assertions you can use are:

  • .to.equal(): Checks if two values are equal.
  • .to.be.a('type'): Checks if a value is of a particular type (e.g., string, number, etc.).
  • .to.be.true: Checks if a value is true.
  • .to.be.false: Checks if a value is false.
  • .to.be.null: Checks if a value is null.
  • .to.have.lengthOf(): Checks if an array or string has a specific length.

Example:

js
expect([1, 2, 3]).to.have.lengthOf(3);

Conclusion

Unit testing is an essential part of software development. By using tools like Mocha and Chai, you can test individual components of your code to ensure they work as expected. Mocha helps you organize and run tests, while Chai provides a powerful assertion library to validate your code's output.

In this class, we learned how to:

  • Set up Mocha and Chai in your project.
  • Write unit tests for simple functions.
  • Use Chai assertions to validate the results of your functions.

Next Steps:

  • Practice writing unit tests for other components of your project.
  • Explore more advanced testing techniques, such as testing asynchronous code with Mocha and Chai.

You said:

WRITE 10 ASSIGNMENTS FROM ABOVE CONCEPT WITH STEP BY STEP SOLUTIONS with proper explanation in details

ChatGPT said:

ChatGPT

Assignments on Unit Testing with Mocha and Chai

Here are 10 assignments based on the concept of unit testing with Mocha and Chai. Each assignment includes a step-by-step explanation and detailed solutions.


Assignment 1: Testing a Simple Addition Function

Task:

Write a unit test for a function add(a, b) that returns the sum of two numbers.

Solution:

1.  Function to Test:

js
const add = (a, b) => a + b;

2.  Test Case:

js
const expect = require('chai').expect;
const add = require('./add'); // Assume add function is in a separate file
 
describe('add()', function() {
  it('should return the sum of two numbers', function() {
    const result = add(2, 3);
    expect(result).to.equal(5);
  });
});

3.  Explanation:

o    We use describe() to group our tests for the add() function.

o    Inside it(), we test whether add(2, 3) equals 5.


Assignment 2: Testing a Subtraction Function

Task:

Write a unit test for a function subtract(a, b) that returns the difference between two numbers.

Solution:

1.  Function to Test:

js
const subtract = (a, b) => a - b;

2.  Test Case:

js
const expect = require('chai').expect;
const subtract = require('./subtract');
 
describe('subtract()', function() {
  it('should return the difference of two numbers', function() {
    const result = subtract(5, 3);
    expect(result).to.equal(2);
  });
});

3.  Explanation:

o    This test checks if the subtract() function correctly calculates the difference between two numbers.


Assignment 3: Testing Multiplication Function

Task:

Write a unit test for a function multiply(a, b) that returns the product of two numbers.

Solution:

1.  Function to Test:

js
const multiply = (a, b) => a * b;

2.  Test Case:

js
const expect = require('chai').expect;
const multiply = require('./multiply');
 
describe('multiply()', function() {
  it('should return the product of two numbers', function() {
    const result = multiply(2, 3);
    expect(result).to.equal(6);
  });
});

3.  Explanation:

o    This test checks if the multiply() function calculates the correct product.


Assignment 4: Testing Division Function with Edge Cases

Task:

Write a unit test for a function divide(a, b) that returns the quotient of two numbers. Handle the edge case where b = 0.

Solution:

1.  Function to Test:

js
const divide = (a, b) => {
  if (b === 0) {
    throw new Error('Cannot divide by zero');
  }
  return a / b;
};

2.  Test Case:

js
const expect = require('chai').expect;
const divide = require('./divide');
 
describe('divide()', function() {
  it('should return the quotient of two numbers', function() {
    const result = divide(6, 2);
    expect(result).to.equal(3);
  });
 
  it('should throw an error when dividing by zero', function() {
    expect(() => divide(6, 0)).to.throw('Cannot divide by zero');
  });
});

3.  Explanation:

o    We handle the division by zero error using a throw.

o    The test checks if the function correctly throws an error when b = 0.


Assignment 5: Testing String Length Function

Task:

Write a unit test for a function getStringLength(str) that returns the length of a given string.

Solution:

1.  Function to Test:

js
const getStringLength = (str) => str.length;

2.  Test Case:

js
const expect = require('chai').expect;
const getStringLength = require('./getStringLength');
 
describe('getStringLength()', function() {
  it('should return the length of the string', function() {
    const result = getStringLength('hello');
    expect(result).to.equal(5);
  });
});

3.  Explanation:

o    The test checks if the getStringLength() function correctly returns the length of a string.


Assignment 6: Testing Array Element Existence

Task:

Write a unit test to check if a specific element exists in an array using includes().

Solution:

1.  Function to Test:

js
const contains = (arr, value) => arr.includes(value);

2.  Test Case:

js
const expect = require('chai').expect;
const contains = require('./contains');
 
describe('contains()', function() {
  it('should return true if the array contains the value', function() {
    const result = contains([1, 2, 3], 2);
    expect(result).to.be.true;
  });
 
  it('should return false if the array does not contain the value', function() {
    const result = contains([1, 2, 3], 4);
    expect(result).to.be.false;
  });
});

3.  Explanation:

o    We use includes() to check if the array contains the specified element and validate the result using Chai assertions.


Assignment 7: Testing an Asynchronous Function

Task:

Write a test for an asynchronous function fetchData() that returns data from an API. Use done() in Mocha to handle the asynchronous nature.

Solution:

1.  Function to Test:

js
const fetchData = (callback) => {
  setTimeout(() => {
    callback('Data received');
  }, 1000);
};

2.  Test Case:

js
const expect = require('chai').expect;
const fetchData = require('./fetchData');
 
describe('fetchData()', function() {
  it('should return data asynchronously', function(done) {
    fetchData((data) => {
      expect(data).to.equal('Data received');
      done(); // Tells Mocha the test is complete
    });
  });
});

3.  Explanation:

o    This test uses done() to tell Mocha when the asynchronous operation is complete.


Assignment 8: Testing Object Properties

Task:

Write a unit test to check if an object has a specific property using Chai's .to.have.property().

Solution:

1.  Function to Test:

js
const person = {
  name: 'John',
  age: 30,
};

2.  Test Case:

js
const expect = require('chai').expect;
 
describe('person object', function() {
  it('should have a property "name"', function() {
    expect(person).to.have.property('name');
  });
 
  it('should have a property "age"', function() {
    expect(person).to.have.property('age').that.is.a('number');
  });
});

3.  Explanation:

o    This test checks if the object has the specified properties and validates their types.


Assignment 9: Testing Array Length

Task:

Write a unit test to check if an array has a specific length using .to.have.lengthOf().

Solution:

1.  Function to Test:

js
const arr = [1, 2, 3, 4];

2.  Test Case:

js
const expect = require('chai').expect;
 
describe('Array length', function() {
  it('should have a length of 4', function() {
    expect(arr).to.have.lengthOf(4);
  });
});

3.  Explanation:

o    The test ensures that the array has the correct number of elements.


Assignment 10: Testing Function with Multiple Parameters

Task:

Write a unit test for a function multiplyAndAdd(a, b, c) that multiplies a and b, then adds c.

Solution:

1.  Function to Test:

js
const multiplyAndAdd = (a, b, c) => a * b + c;

2.  Test Case:

js
const expect = require('chai').expect;
 
describe('multiplyAndAdd()', function() {
  it('should multiply a and b, then add c', function() {
    const result = multiplyAndAdd(2, 3, 4);
    expect(result).to.equal(10);
  });
});

3.  Explanation:

o    The test verifies that the function correctly performs multiplication and addition.


These assignments will help students practice the various aspects of unit testing with Mocha and Chai, from testing basic arithmetic functions to handling asynchronous operations and working with arrays and objects.

You said:

WRITE 50 no of MCQs only FROM ABOVE CONCEPT with explanation

ChatGPT said:

ChatGPT

Here are 50 Multiple Choice Questions (MCQs) based on the concept of Unit Testing with Mocha and Chai, along with explanations for each answer:


1. Which of the following is the main purpose of unit testing?

a) To test the entire system
b) To test individual components or functions
c) To deploy the application
d) To check the user interface

Answer: b) To test individual components or functions
Explanation: Unit testing is aimed at testing small units or functions in isolation to ensure they work as expected.


2. What does Mocha provide in unit testing?

a) Assertion library
b) Test framework for organizing tests
c) A GUI interface for testing
d) A tool to monitor performance

Answer: b) Test framework for organizing tests
Explanation: Mocha is a testing framework that provides structure and utilities for writing and organizing tests.


3. What does the Chai assertion library allow you to do?

a) Organize tests into suites
b) Write tests for database queries
c) Validate the output of your functions
d) Compile code

Answer: c) Validate the output of your functions
Explanation: Chai is an assertion library used in Mocha for validating whether the actual output of a function matches the expected result.


4. Which method in Mocha is used to group related tests?

a) it()
b) before()
c) describe()
d) done()

Answer: c) describe()
Explanation: describe() is used to group related tests together for better organization.


5. Which of the following is an example of a Chai assertion?

a) assert.equal()
b) describe()
c) it()
d) before()

Answer: a) assert.equal()
Explanation: assert.equal() is a Chai assertion used to check if two values are equal.


6. What is the correct way to run Mocha tests from the terminal?

a) npm start
b) npm test
c) mocha run
d) mocha start

Answer: b) npm test
Explanation: The command npm test runs Mocha tests if Mocha is properly set up in the project.


7. What function does Mocha’s it() perform?

a) It groups related tests
b) It contains a single test case
c) It defines the setup of tests
d) It cleans up after tests

Answer: b) It contains a single test case
Explanation: it() is used to define a single test case within a suite.


8. Which of the following is the default assertion style in Chai?

a) Should
b) Expect
c) Assert
d) None of the above

Answer: b) Expect
Explanation: The default assertion style in Chai is expect, which allows for a readable, human-friendly way of asserting values.


9. What is the purpose of Mocha’s beforeEach()?

a) It runs before all tests
b) It runs after all tests
c) It runs before each test
d) It cleans up after each test

Answer: c) It runs before each test
Explanation: beforeEach() is a hook in Mocha that runs before each test in a test suite.


10. How can you handle asynchronous tests in Mocha?

a) Using done() callback
b) Using expect()
c) Using assert()
d) Using setTimeout()

Answer: a) Using done() callback
Explanation: Mocha provides the done() callback to handle asynchronous tests by signaling when the test is complete.


11. Which of the following is used to check equality in Chai assertions?

a) expect.to.equal()
b) assert.toEqual()
c) it.to.equal()
d) describe.to.equal()

Answer: a) expect.to.equal()
Explanation: expect.to.equal() is used to check if two values are equal in Chai's assertion style.


12. Which method would you use to check if a number is a specific type using Chai?

a) .to.be.true
b) .to.be.a('number')
c) .to.equal()
d) .to.be.null

Answer: b) .to.be.a('number')
Explanation: Chai’s .to.be.a('number') is used to check if a value is of type number.


13. What does the .to.have.property() assertion in Chai check?

a) Whether a string contains a substring
b) Whether an object has a specific property
c) Whether an array contains a specific element
d) Whether a number is divisible by another number

Answer: b) Whether an object has a specific property
Explanation: .to.have.property() checks if the given object contains the specified property.


14. Which of the following is used to check if an array has a specific length in Chai?

a) .to.have.length()
b) .to.length()
c) .to.have.lengthOf()
d) .to.lengthOf()

Answer: c) .to.have.lengthOf()
Explanation: .to.have.lengthOf() is used to assert that an array or string has a specific length.


15. What does Mocha's before() hook do?

a) Runs before each test case
b) Runs once before all tests
c) Runs once after all tests
d) Runs after each test case

Answer: b) Runs once before all tests
Explanation: before() is used for global setup before all tests are run.


16. Which function can be used to assert that a function throws an error in Chai?

a) .to.throw()
b) .to.be.true()
c) .to.have.property()
d) .to.equal()

Answer: a) .to.throw()
Explanation: .to.throw() is used in Chai to assert that a function throws an expected error.


17. What is the use of done() in an asynchronous test in Mocha?

a) To indicate that the test is complete
b) To skip a test
c) To check the equality of values
d) To check for errors

Answer: a) To indicate that the test is complete
Explanation: done() is called in asynchronous tests to signal that the test is complete.


18. In Mocha, which method is used to clean up after all tests?

a) afterEach()
b) before()
c) after()
d) beforeEach()

Answer: c) after()
Explanation: after() is used to perform cleanup tasks once after all tests have run.


19. What is the purpose of the .to.be.null assertion in Chai?

a) To check if a value is true
b) To check if a value is equal to 0
c) To check if a value is null
d) To check if a value is undefined

Answer: c) To check if a value is null
Explanation: .to.be.null checks if a value is null.


20. Which of the following is used to check whether an array contains a specific element?

a) .to.include()
b) .to.have.property()
c) .to.be.null()
d) .to.equal()

Answer: a) .to.include()
Explanation: .to.include() is used to check if an array contains a specific element.


21. How do you test if an array has a specific number of elements in Chai?

a) .to.have.lengthOf()
b) .to.have.sizeOf()
c) .to.lengthOf()
d) .to.sizeOf()

Answer: a) .to.have.lengthOf()
Explanation: .to.have.lengthOf() checks if an array has the specified number of elements.


22. In Mocha, which method is used to run code before every test in the suite?

a) before()
b) afterEach()
c) beforeEach()
d) after()

Answer: c) beforeEach()
Explanation: beforeEach() runs before every individual test in the suite.


23. What happens if an assertion fails in Mocha?

a) The test passes
b) Mocha moves to the next test
c) Mocha stops executing further tests
d) Mocha logs the failure but continues testing

Answer: c) Mocha stops executing further tests
Explanation: If an assertion fails, Mocha will stop executing the current test, but it will proceed with the next tests.


24. What is the purpose of the describe() function in Mocha?

a) To assert values in tests
b) To group related tests into a test suite
c) To run an individual test
d) To define the setup logic

Answer: b) To group related tests into a test suite
Explanation: describe() is used to group related tests into a suite.


25. Which of the following is a correct way to import Chai in your test file?

a) const chai = require('mocha');
b) const chai = require('chai');
c) import chai from 'chai';
d) import { chai } from 'chai';

Answer: b) const chai = require('chai');
Explanation: Chai is imported using require('chai') in Node.js.


26. Which assertion is used to check if two values are strictly equal in Chai?

a) .to.equal()
b) .to.eql()
c) .to.be.a()
d) .to.deep.equal()

Answer: a) .to.equal()
Explanation: .to.equal() checks for strict equality, i.e., both values must be identical.


27. Which Mocha function is used to run a test only once after all tests in the suite?

a) beforeEach()
b) after()
c) afterEach()
d) before()

Answer: b) after()
Explanation: after() runs once after all tests in the suite have finished.


28. In Chai, how would you check that an array is empty?

a) .to.be.empty
b) .to.be.null
c) .to.equal([])
d) .to.have.length(0)

Answer: a) .to.be.empty
Explanation: .to.be.empty checks if an array is empty.


29. Which Mocha method is used to execute code after each test in the suite?

a) afterEach()
b) beforeEach()
c) before()
d) after()

Answer: a) afterEach()
Explanation: afterEach() runs after every individual test in the suite.


30. What type of function is typically tested using unit tests?

a) Integration functions
b) Large system components
c) Individual functions and methods
d) User interfaces

Answer: c) Individual functions and methods
Explanation: Unit tests typically test small, individual functions or methods in isolation.


31. What does expect(5).to.be.a('number') check in Chai?

a) Whether the value is 5
b) Whether the value is a number
c) Whether the value is greater than 5
d) Whether the value is a string

Answer: b) Whether the value is a number
Explanation: This assertion checks if the value 5 is of type number.


32. Which function is used to run tests only in Mocha?

a) describe()
b) it()
c) run()
d) done()

Answer: b) it()
Explanation: it() is used to define individual test cases in Mocha.


33. How do you assert that a function throws an error in Mocha/Chai?

a) expect(function).to.throw()
b) expect(function).to.throwError()
c) assert.throw()
d) assert.error()

Answer: a) expect(function).to.throw()
Explanation: The correct syntax to check for errors in Chai is expect(function).to.throw().


34. What is the role of done() in asynchronous testing?

a) To run tests sequentially
b) To signal when a test is complete
c) To skip a test
d) To group tests together

Answer: b) To signal when a test is complete
Explanation: done() is used in asynchronous tests to tell Mocha when the test is complete.


35. What does describe('Test Suite', function() {...}) do in Mocha?

a) Defines a group of related tests
b) Runs individual tests
c) Handles asynchronous tests
d) Asserts the output of tests

Answer: a) Defines a group of related tests
Explanation: describe() is used to group related tests into a suite.


36. How would you test a promise in Mocha?

a) Use done() for promises
b) Use await with async functions
c) Use expect().to.be.fulfilled()
d) Use callbacks only

Answer: b) Use await with async functions
Explanation: Promises can be tested using async/await to handle asynchronous code.


37. How would you assert that a function returns a value of true?

a) expect(value).to.equal(true)
b) expect(value).to.be.true()
c) assert.true(value)
d) all of the above

Answer: d) all of the above
Explanation: All of these assertions correctly check if a value is true.


38. How do you ensure a test case runs successfully without throwing errors?

a) Use the assert library
b) Ensure the function does not throw any exceptions
c) Always use done()
d) Test the value return

Answer: b) Ensure the function does not throw any exceptions
Explanation: Tests should check that a function executes without throwing any unexpected errors.


39. Which hook is used for one-time setup before all tests run?

a) beforeEach()
b) before()
c) afterEach()
d) after()

Answer: b) before()
Explanation: before() is used for one-time setup before any test is run.


40. In which situation would you use expect().to.be.true?

a) To check if a number is positive
b) To check if a string matches
c) To check if a boolean is true
d) To check if an object contains properties

Answer: c) To check if a boolean is true
Explanation: This assertion checks if a boolean value is true.


41. Which of the following is used to check if an object is empty in Chai?

a) .to.be.empty
b) .to.equal()
c) .to.have.property()
d) .to.be.null

Answer: a) .to.be.empty
Explanation: .to.be.empty checks whether an object is empty (has no properties).


42. How do you handle errors in Mocha tests?

a) Using the done() function
b) Using try/catch blocks
c) Using asynchronous callbacks
d) All of the above

Answer: d) All of the above
Explanation: Mocha allows handling errors using the done() function, try/catch, or asynchronous callbacks.


43. What does .to.deep.equal() check in Chai?

a) Strict equality
b) Equality of arrays or objects (deep comparison)
c) Whether two arrays are the same size
d) Whether an object has a property

Answer: b) Equality of arrays or objects (deep comparison)
Explanation: .to.deep.equal() checks if the arrays or objects are deeply equal.


44. What is the role of the afterEach() function in Mocha?

a) To execute code before each test
b) To clean up after each test
c) To run after all tests
d) To group tests

Answer: b) To clean up after each test
Explanation: afterEach() is used to run cleanup tasks after each test in the suite.


45. How do you handle asynchronous code in Mocha without done()?

a) Using async/await
b) Using promises
c) Using callbacks
d) All of the above

Answer: d) All of the above
Explanation: Mocha supports async/await, promises, and callbacks to handle asynchronous code.


46. What is the default behavior of Mocha when an assertion fails?

a) It stops the test execution immediately
b) It skips the failed test
c) It runs the next test
d) It prints an error and continues with the next test

Answer: a) It stops the test execution immediately
Explanation: Mocha stops executing the current test immediately when an assertion fails.


47. How do you run a single test in Mocha?

a) mocha testName
b) mocha --single
c) mocha --grep testName
d) mocha run testName

Answer: c) mocha --grep testName
Explanation: The --grep flag can be used to run specific tests that match a regular expression or name.


48. Which of the following would you use to test whether a function calls another function?

a) Sinon.js
b) Mocha
c) Chai
d) Jest

Answer: a) Sinon.js
Explanation: Sinon.js is used to spy on, mock, or stub functions in Mocha tests.


49. What is the Mocha feature that allows for skipping tests?

a) describe.skip()
b) it.skip()
c) after.skip()
d) before.skip()

Answer: b) it.skip()
Explanation: it.skip() is used to skip a specific test case in Mocha.


50. In Chai, which assertion is used to check if a string contains a substring?

a) .to.include()
b) .to.have.lengthOf()
c) .to.have.property()
d) .to.deep.equal()

Answer: a) .to.include()
Explanation: .to.include() is used to check if a string contains a given substring.


 

No comments:

Post a Comment

Search This Blog

Powered by Blogger.