6 Classes + Testing

Classes + Testing

Objective

  1. ECMAScript modules (ESM).
  2. Classes, constructors, and inheritance.
  3. Fields, methods, and encapsulation.
  4. Static fields and methods.
  5. Abstract classes and methods?
  6. JavaScript Object Notation (JSON) for serialization and deserialization.
  7. Unit testing using Mocha (opens in a new tab) and Chai (opens in a new tab).

1 Modules

Build a simple banking application that manages accounts and provides various operations such as depositing to, withdrawing from, adding, removing, and retrieving accounts.

  1. Initialize your directory as a package using npm init, then set the module format to ESM in package.json: { "type": "module" }.

  2. Create a Bank module, bank.js, where you declare an array, accounts, of object literals to store the following accounts:

    idbalancetype
    08a45dd424502.30Savings
    a9e24658414,100.00Current
    7160dca60134,420.55Current
    2efde49d9d61,023.69Savings
  3. Implement and export the following functions in the Bank module:

    1. add(account) adds either a Savings or Current account to the array of accounts and returns its identifier.

      The identifier is generated using the Nano ID (opens in a new tab) (nanoid (opens in a new tab)) package.

    2. getAll() return all accounts.

    3. get(id) returns an account by identifier.

    4. remove(id) deletes an account by identifier.

    5. deposit(id, amount) adds the amount to the account balance.

    6. withdraw(id, amount) subtracts the amount from the account balance, if it has sufficient balance.

    7. totalBalance() returns the total balance for all accounts.

    8. deductFee(fee) deducts a monthly fee from the balance of all Current accounts.

    9. distributeBenefit(percentage) increases the balance of all Savings accounts by a benefit percentage.

    10. toJSON() returns the array of accounts as a JSON string.

    11. fromJSON(json) parses the JSON string and returns an array of accounts.

  4. Write an application, app.js, to test the Bank module by creating a couple of Current and Savings accounts, then performing a few deposits and withdrawals:

    1. Charge a monthly fee of 10.
    2. Display the total balance of all accounts after charging the monthly fee.
    3. Distribute a 6% benefit.
    4. Display the total balance of all accounts after distributing the benefit.
    5. Display the list of accounts in JSON format.

2 Classes

Classes in JavaScript are, for the most part, syntactic sugar for prototype-based inheritance (opens in a new tab).

UML diagram for Bank, BankAccount, CurrentAccount, and SavingsAccount classesBank#accountsconstructor(accounts)getaccounts()get(id)add(account)remove(id)totalBalance()toString()toJSON()BankAccount#id#balanceconstructor(account)getid()getbalance()deposit(amount)withdraw(amount)toString()toJSON()#generateId()CurrentAccount#feeconstructor(account)charge()toString()toJSON()getfee()setfee(amount)toJSON()SavingsAccount#benefitconstructor(account)distribute()toString()toJSON()getbenefit()setbenefit(amount)toJSON()

Rewrite the application from 1 Modules using the classes Bank, BankAccount, CurrentAccount, and SavingsAccount, as specified in the UML diagram, where a Bank is composed of multiple BankAccounts and each BankAccount is either a CurrentAccount or a SavingsAccount.

Complete the 3 Exceptions guide to learn more about throwing and catching exceptions.

3 Unit Testing

Install the Mocha Test Explorer (opens in a new tab) and the ES6 Mocha Snippets (opens in a new tab) extensions for Visual Studio Code.

Mocha (opens in a new tab) is a test framework that supports test-driven development (TDD) by providing a simple interface for writing and running tests. Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct test cases.

Chai (opens in a new tab) is an assertion library that can follow a test-driven or behavior-driven development (BDD), can be paired with any testing framework, and supports plugins such as chai-superagent (opens in a new tab) and sinon-chai (opens in a new tab).

There are numerous testing tools, frameworks, and libraries listed under Links → Testing.

  1. Install the convert (opens in a new tab) package using npm install convert, then import and use is to convert a few units:

    index.js
    import convert from "convert";
     
    console.log("360 s = %d m", convert(360, "seconds").to("minutes"));
    console.log("5 km = %f mi", convert(5, "kilometers").to("nautical miles"));
    console.log("12 lb = %d oz", convert(12, "pounds").to("ounces"));
    console.log("8,192 B = %d KiB", convert(8192, "bytes").to("KiB"));
    console.log("10 atm = %f kPa", convert(10, "atmospheres").to("kPa"));
    console.log("451 °F = %f °C", convert(451, "fahrenheit").to("celsius"));
  2. Install Mocha (opens in a new tab) as local development dependency:

    npm install --save-dev mocha
  3. Create a test/convert.spec.js test specification file, that uses mocha and assert, to test some of the unit conversions provided by convert:

    test/convert.spec.js
    import convert from "convert";
    import assert from "assert";
     
    describe("convert", function () {
      describe("time", function () {
        it("should convert 60 s to 1 m", function () {
          assert.equal(convert(60, "seconds").to("minutes"), 1);
        });
        it("should convert 1h to 3,600 s", function () {
          assert.equal(convert(1, "hours").to("seconds"), 3600);
        });
      });
      describe("mass", function () {
        it("should convert 1 kg to 2.2 lb", function () {
          assert.equal(convert(1, "kg").to("pounds"), 2.2);
        });
      });
    });
  4. Run the tests using npx mocha and fix the failing test case using Number.toFixed() (opens in a new tab).

  5. Add a script to package.json to run the tests using npm test:

    package.json
    {
      "scripts": {
        "test": "mocha"
      }
    }
  6. Install Chai (opens in a new tab) as a local development dependency:

    npm install --save-dev chai
  7. Rewrite the test assertions in a BDD-style using chai.expect() (opens in a new tab):

    test/convert.spec.js
    import convert from "convert";
    import { describe, it } from "mocha";
    import { expect } from "chai";
     
    describe("convert", function () {
      describe("time", function () {
        it("should convert 60 s to 1 m", function () {
          expect(convert(60, "seconds").to("minutes")).to.be.equal(1);
        });
        it("should convert 1 h to 3600 s", function () {
          expect(convert(1, "hours").to("seconds")).to.be.equal(3600);
        });
      });
      describe("mass", function () {
        it("should convert 1 kg to 2.2 lb", function () {
          expect(convert(1, "kg").to("pounds")).to.be.equal(2.2);
        });
      });
      describe("best", function () {
        it("should convert to best with unit and quantity properties", function () {
          expect(convert(1500, "meters").to("best")).to.have.own.property(
            "unit",
          );
          expect(convert(1500, "meters").to("best")).to.have.own.property(
            "quantity",
          );
        });
      });
    });
  8. Write unit tests, using Mocha + Chai, for each method of the Bank class and run them.

Resources