Test Driven Development (TDD) in a nutshell

Every project has somewhere in the src folder a file called utils.js, Utils.java, utils.py, etc. A couple of days ago I was looking for a way to generate a random float number between two integer numbers. Utils.xx was a good place to put a function called getRandomNumberBetween(min,max).

In my case I was working with Node.js, so my function was

module.exports.getRandomNumberBetween = function (min, max) {
    return Math.random() * (max - min) + min;
}

Seems a super basic function but it hides several scenarios to test.

  • What happen if min is null
  • And max?
  • What happen if any of them is negative?
  • What happen if min is greater than max?
  • What if there are strings?

Sometimes simple function involves more time testing than implement it

I found this example a good way to explain what TDD is.

Formally, TDD means Test Driven Development but in your day by day means “to write tests before your main code”. Let’s use our random function example to explain TDD steps.

The first step is to think what I want:

I want a method that receives two integer numbers and returns a random float number between them

The second step is to start writing test cases

describe("getRandomNumberBetween", function() {
    it("should return a random number between positive range", function(done) {
        const min = 4;
        const max = 5;
        const random = Utils.getRandomNumberBetween(min, max);
        assert.isTrue(random >= min);
        assert.isTrue(random <= max);

        done();
    });

    it("should return a random number between negative range", function(done) {
        const min = -8;
        const max = -1;
        const random = Utils.getRandomNumberBetween(min, max);
        assert.isTrue(random >= min);
        assert.isTrue(random <= max);

        done();
    });

    it("should get an error with null min", function(done) {
        const min = null;
        const max = 10;
        try {
            Utils.getRandomNumberBetween(min, max);
            assert.fail("should throw an error");
        } catch (e) {
            assert.equal(e.message, "min is empty");
        }

        done();
    });

    it("should get an error with null max", function(done) {
        const min = 10;
        const max = null;
        try {
            Utils.getRandomNumberBetween(min, max);
            assert.fail("should throw an error");
        } catch (e) {
            assert.equal(e.message, "max is empty");
        }

        done();
    });

    it("should get an error with undefined min", function(done) {
        let min;
        const max = 10;
        try {
            Utils.getRandomNumberBetween(min, max);
            assert.fail("should throw an error");
        } catch (e) {
            assert.equal(e.message, "min is empty");
        }

        done();
    });

    it("should get an error with undefined max", function(done) {
        const min = 10;
        let max;
        try {
            Utils.getRandomNumberBetween(min, max);
            assert.fail("should throw an error");
        } catch (e) {
            assert.equal(e.message, "max is empty");
        }
        done();
    });
});

And the last step is to write the code that makes all the tests pass

/**
 *
 * @param min
 * @param max
 * @returns {number} a number between min and max
 */
module.exports.getRandomNumberBetween = function (min, max) {
    if (this.isEmpty(min)) {
        throw Error('min is empty');
    }
    if (this.isEmpty(max)) {
        throw Error('max is empty');
    }
    if (isNaN(min)) {
        throw Error('min is Nan');
    }
    if (isNaN(max)) {
        throw Error('max is Nan');
    }
    return Math.random() * (max - min) + min;
};

Steps 2 and 3 are iterations that you will stop when you cover all your scenarios and all tests are green.

Did you see? A simple one-line method triggered a big test suite!

If you are using Node.js, I strongly recommend the package nyc to see the coverage of your source code. That package will help you a lot if you forgot to test a particular scenario.

Photo by Markus Spiske on Unsplash

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s