Understanding the TDD process

TDD consists of a rapid repetition of the following steps:

  1. Identify the smallest functional unit of your feature that has not yet been implemented.
  2. Identify a test case and write a test for it. You may want to have test cases that cover the happy path, which is the default scenario that produces no errors or exceptions, as well as unhappy paths, including dealing with edge cases.
  3. Run the test and see it fail.
  4. Write the minimum amount of code to make it pass.
  5. Refactor the code.

For example, if we want to build a math utility library, then our first iteration of the TDD cycle may look like this:

Here, we are using the assert module from Node, as well as the describe and it syntax provided by the Mocha testing framework. We will clarify their syntax in detail in Chapter 5Writing End-to-End Tests. In the meantime, you may simply treat the following test code as pseudocode.

  1. Pick a feature: For this example, let's pick the sum function, which simply adds numbers together.
  2. Define a test case: When running the sum function with 15 and 19 as the arguments, it should return 34:
var assert = require('assert');
var sum = require('sum');
describe('sum', function() {
it('should return 34 when 15 and 19 are passed in', function() {
assert.equal(34, sum(15, 19));
});
});
  1. Run the test: It fails because we haven't written the sum function yet.
  1. Write the code: Write the sum function that will allow us to pass the test:
const sum = function(x, y) {
return x + y;
}
  1. Refactor: No refactoring needed.

This completes one cycle of the TDD process. In the next cycle, we will work on the same function, but define additional test cases:

  1. Pick a feature: we'll continue developing the same sum function. 
  2. Define a test case: this time, we will test it by supplying three arguments, 56, 32 and 17, we expect to receive the result 105:
describe('sum', function() {
...
it('should return 105 when 56, 32 and 17 are passed in', function() {
assert.equal(105, sum(56, 32, 17));
});
});
  1. Run the test: it fails because our current sum function only takes into account the first two parameters. 
  1. Write the code: update the sum function to take into account the first three parameters:
const sum = function(x, y, z) {
return x + y + z;
}
  1. Refactor: improve the function by making it work for any number of function parameters:
const sum = function(...args) => [...args].reduce((x, y) => x + y, 0);

Note that calling with just two arguments would still work, and so the original behavior is not altered.

Once a sufficient number of test cases have been completed, we can then move on to the next function, such as multiply.