Test-Driven Development is a software development process that relies on the repetition of a very short development cycle: Requirements are turned into very specific test cases, then the software is improved to pass the new tests.
- Add a test
- Run all tests and see if the new test fails
- Write the code
- Run tests
- Refactor code
- Repeat
Thereby the cornerstone of this process is represented by the Unit Test.
Mocha and Chai
- In Node.js a wide used test framework is Mocha: it makes synchronous and asynchronous testing simple and straightforward, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct test cases.
- The assertion library we will use is Chai: it has several interfaces that allow the developer to choose the most comfortable (should, expect, assert).
Roman Numbers
A Roman number represents an integer (Hindu-Arabic numerals) using a small set of symbols:
Roman Numeral | Hindu-Arabic Equivalent |
---|---|
I | 1 |
V | 5 |
X | 10 |
L | 50 |
C | 100 |
D | 500 |
M | 1000 |
There are a few rules for writing numbers with Roman numerals.
- Repeating a numeral up to three times represents addition of the number. For example, III represents 1 + 1 + 1 = 3. Only I, X, C, and M can be repeated; V, L, and D cannot be, and there is no need to do so.
- Writing numerals that decrease from left to right represents addition of the numbers. For example, LX represents 50 + 10 = 60 and XVI represents 10 + 5 + 1 = 16.
- To write a number that otherwise would take repeating of a numeral four or more times, there is a subtraction rule. Writing a smaller numeral to the left of a larger numeral represents subtraction. For example, IV represents 5 - 1 = 4 and IX represents 10 - 1 = 9. To avoid ambiguity, the only pairs of numerals that use this subtraction rule are:
Roman Numeral | Hindu-Arabic Equivalent |
---|---|
IV | 4 = 5 - 1 |
IX | 9 = 10 - 1 |
XL | 40 = 50 - 10 |
XC | 90 = 100 - 10 |
CD | 400 = 500 - 100 |
CM | 900 = 1000 - 100 |
Following these rules, every Hindu-Arabic number between 1 and 3999 (MMMCMXCIX) can be represented as a Roman numeral.
Requirements
The Roman Number Library to build will have to take a value in input (a Roman Number or an Hindu-Arabic number), and will have to return an object containing two methods:
- toInt()
- toString()
|
|
- If the value passed is null or empty, it should throw a ‘value required’ exception error (e.g. ‘throw new
Error(‘value required’);’ ). - If the value passed is outside of 1 to 3999, it should throw an ‘invalid range’ exception error.
- If the value passed is invalid, it should throw an ‘invalid value’ exception error.
- If the library is called as a function (i.e. without the new prefix), it must still pass back a new object.
Kick-off
Let’s kick our application off!
Create the folder RomanNumber:$ mkdir RomanNumber
$ cd RomanNumber
Initialize the application:$ npm init
Add Mocha framework:$ npm install --save-dev mocha
Add Chai:$ npm install --save-dev chai
Create the empty file RomanNumber.js
Create the folder test:$ mkdir test
$ cd test
Create and launch the first test
Under the test folder, create the file testRomanNumber.js with the following code:
In this piece of code we include Chai with its three interfaces (should, expect, assert).
Then we include RomanNumber.js (which is still empty).
“describe“ is used merely for grouping test cases, which you can nest as deep.
“it“ is a test case: here the very first test case is about invoking the library’s constructor let romanNumber = new RomanNumber(1)
and check that it returns an object assert.isObject(romanNumber)
.
To launch the test, just type:$ npm test
We have an error stating that RomanNumber is not a constructor: this was the expected error hence our library code is still empty.
Init Library
In order to pass the test, let’s add this simple piece of code to out Roman Number library (RomanNumber.js):
Now, let’s run the test again:$ npm test
More to come
In Pt.2 we will add more tests based on the requirements we defined, and the code to pass those tests.
Check out the Roman Library Repository if you cannot wait for the last chapter of this blog