Classes + Testing
Objectives
- ECMAScript modules (ESM).
- Classes, constructors, and inheritance.
- Fields, methods, and encapsulation.
- Static fields and methods.
- Abstract classes and methods?
- JavaScript Object Notation (JSON) for serialization and deserialization.
- Unit testing using test runners (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.
-
Initialize your directory as a package using
bun init, then (optionally) set the module format to ESM inpackage.json:{ "type": "module" }. -
Create a
Bankmodule,bank.js, where you declare an array,accounts, of object literals to store the following accounts:idbalancetype08a45dd424 502.30 Savings a9e2465841 4,100.00 Current 7160dca601 34,420.55 Current 2efde49d9d 61,023.69 Savings -
Implement and export the following functions in the
Bankmodule:-
add(account)adds either aSavingsorCurrentaccount 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. -
getAll()return all accounts. -
get(id)returns an account by identifier. -
remove(id)deletes an account by identifier. -
deposit(id, amount)adds the amount to the account balance. -
withdraw(id, amount)subtracts the amount from the account balance, if it has sufficient balance. -
totalBalance()returns the total balance for all accounts. -
deductFee(fee)deducts a monthly fee from the balance of allCurrentaccounts. -
distributeBenefit(percentage)increases the balance of allSavingsaccounts by a benefit percentage. -
toJSON()returns the array of accounts as a JSON string. -
fromJSON(json)parses the JSON string and returns an array of accounts.
-
-
Write an application,
app.js, to test theBankmodule by creating a couple ofCurrentandSavingsaccounts, then performing a few deposits and withdrawals:- Charge a monthly fee of
10. - Display the total balance of all accounts after charging the monthly fee.
- Distribute a
6%benefit. - Display the total balance of all accounts after distributing the benefit.
- Display the list of accounts in JSON format.
- Charge a monthly fee of
2 Classes
Classes in JavaScript are, for the most part, syntactic sugar for prototype-based inheritance (opens in a new tab).
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
Bun’s test runner (opens in a new tab) is a built-in, Jest-compatible testing framework that supports test-driven development (TDD) and behavior-driven development (BDD). It provides describe, test, and expect functions with no external dependencies required.
Install the Bun for Visual Studio
Code (opens in a new tab)
extension for live in-editor error messages, test runner and debugger support,
and running scripts from package.json.
There are numerous testing tools, frameworks, and libraries listed under Links → Testing.
-
Install the
convert(opens in a new tab) package usingbun add convert, then import and use it to convert a few units:index.jsimport 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")); -
Create a
test/convert.test.jstest specification file using Bun’s built-in test runner to test some of the unit conversions provided byconvert:test/convert.test.jsimport convert from "convert"; import { describe, test, expect } from "bun:test"; describe("convert", () => { describe("time", () => { test("should convert 60 s to 1 m", () => { expect(convert(60, "seconds").to("minutes")).toBe(1); }); test("should convert 1 h to 3600 s", () => { expect(convert(1, "hours").to("seconds")).toBe(3600); }); }); describe("mass", () => { test("should convert 1 kg to 2.2 lb", () => { expect(convert(1, "kg").to("pounds")).toBe(2.2); }); }); }); -
Run the tests using
bun testand fix the failing test case usingNumber.toFixed()(opens in a new tab). -
Add more test cases using other matchers (opens in a new tab) provided by Bun:
test/convert.test.jsimport convert from "convert"; import { describe, test, expect } from "bun:test"; describe("convert", () => { describe("time", () => { test("should convert 60 s to 1 m", () => { expect(convert(60, "seconds").to("minutes")).toBe(1); }); test("should convert 1 h to 3600 s", () => { expect(convert(1, "hours").to("seconds")).toBe(3600); }); }); describe("mass", () => { test("should convert 1 kg to 2.2 lb", () => { expect(Number(convert(1, "kg").to("pounds").toFixed(1))).toBe(2.2); }); }); describe("best", () => { test("should convert to best with unit and quantity properties", () => { expect(convert(1500, "meters").to("best")).toHaveProperty("unit"); expect(convert(1500, "meters").to("best")).toHaveProperty("quantity"); }); }); }); -
Write unit tests for each method of the
Bankclass and run them usingbun test.
Structure
Resources
- MDN: Using classes (opens in a new tab), Working with objects (opens in a new tab), Keyed collections (opens in a new tab), Inheritance and the prototype chain (opens in a new tab), JavaScript modules (opens in a new tab), Classes (opens in a new tab),
new.target(opens in a new tab),constructor(opens in a new tab) - Eloquent JavaScript | The Secret Life of Objects (opens in a new tab)
- ES modules: A cartoon deep-dive (opens in a new tab)
- TDD vs BDD vs ATDD: Key Differences (opens in a new tab)