TDD and BDD

2016-06-14

Past a few days been hectic resulting from the fairly complicated overall Visa application process for Spain (need it for EuroPython’16 ). Meanwhile, I have been reading about TDD or Test Driven Development and BDD or Behaviour Driven Development to write tests for the controllers using Mocha - a testing framework, Chai - a BDD assertion library and Karma - a test runner. Test runner can run tests based on different test frameworks - in this case. Mocha. Their documentaions might seem bloating at first sight. I felt the same when I started reading about them. But it’s actually simple once you’ve understood the concept behind TDD. Through this blog I shall try to explain why we should follow TDD approach and also write some basic tests using Mocha and Chai together. Let’s drop karma for a while.

Why TDD?

Originally, TDD meant writing tests before the actual implementation. ( But you may write tests afterwards too (not a good approach though). Now, the question comes - how can one write tests for something that haven’t been implemented yet. Makes sense, isn’t it? Well usually when you test modules/functions , you already know your expectations. For instance, If I am going to write a function that checks if a given real number is a power of 2, I already know the outcome. In this case it’s a boolean value - True for power of 2 and False otherwise. So, you may very well write tests using this information.
There are many advantages of adopting TDD. First being avoiding Regression bugs. Regression bug is a bug that had been fixed in the past and then occurred again. For instance, we change obviously unrelated piece of code and therefore we do not check some old problem, because we do not expect that problem to occur again. Once we have an automated test for this bug, it will not happen again because we can easily run all tests instead of manually trying only the parts that are obviously related to the change we made.
Another reason being Refactoring. The code architecture may require changes to a project requirements. Tests prove whether the code still works, even after a major refactoring.

Get started

Installation

You may install karma using npm - node package manager. To install the Karma plugins for Mocha and Chai. Also, it’d be nice to use PhantomJS for headless testing. Let’s create a pacakge.json file and add the dependencies to it. It might look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
“devDependencies”: {
“chai”: “^3.5.0”,
“karma”: “^0.13.21”,
“karma-chai”: “^0.1.0”,
“karma-jasmine”: “^1.0.2”,
“karma-mocha”: “^0.2.2”,
“mocha”: “^2.4.5”,
“karma-phantomjs-launcher”: “^1.0.0”,
“phantomjs-prebuilt”: “^2.1.4”
},
“scripts”: {
“test”: “./node_modules/.bin/karma start”
}
}

Now, run npm install to fetch and install the dependencies.
Also, to make it easier to run karma from the command line you can install karma-cli globally, which will run the local version without having to specify the path to karma (node node_modules/karma/bin/karma):

1
npm install -g karma-cli

Karma needs a configuration file. Create one by running karma init and answering the simple question. Make sure you specify Mocha as your testing framework. Also, mention source and tests files location accordingly. In my case it’s in ./app/**/*.js for source and ./tests/**/*Spec.js for tests.
Let’s create two empty files app/powerOfTwo.js and tests/powerOfTwoSpec.js. It’d look like

1
2
3
4
├── app
│ └── powerOfTwo.js
└── tests
└── powerOfTwoSpec.js

Once you’re done, you have karma-conf.js. To get Chai included in the test pipeline, edit karma-conf.js and add it to the frameworks setting. Also to be able to use PhantomJS mention it in browsers.

1
2
frameworks: [‘mocha’, ‘chai’]
browsers: [‘PhantomJS’]

Running karma start will execute the default karma-conf.js. You can have multiple configuration files which can be run by specifying the name of the configuration file. karma start <conf-file-name>.

Enough installation. Let’s get down to writing tests.

Writing tests

By default, you can use Mocha’s assertion module (which is in fact Node’s regular assertion module) to run your tests. However, it can be quite limiting. This is where assertion libraries like Chai enter the frame. Writing a test is like constructing a perfect sentence in English. Don’t believe me? Hm see yourself. We describe an umbrella of tests, and state some expected outputs for various tests under that umbrella.

Write this in tests/powerOfTwoSpec.js.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
describe(‘powerOfTwo’, function(){ // The Umbrella test. You can create as many depending on your code architecture

// Individual tests
it(‘powerOfTwo should return a boolean value’, function() {
powerOfTwo(64).should.be.a(‘boolean’); // I wish Visa process was as simple as this!!
});

it(‘powerOfTwo should return true for power of 2’, function(){
expect(powerOfTwo(64)).to.be.true;
});

it(‘powerOfTwo should return false for non power of 2’, function(){
expect(powerOfTwo(31)).to.be.false;
});
});

Note that we haven’t created the powerOfTwo function yet. But looking at the tests, we can say how our function is expected to behave. That’s TDD and BDD for you in the simplest form.

Now let’s write our powerOfTwo function in powerOfTwo.js

1
2
3
var powerOfTwo = function(num) {
return num && (!(num & (num-1)));
}

Finally, we may run the tests running npm test in project root directory.

I hope that was simple and introduced you to the basics of TDD/BDD. Go ahead and try yourself.
Explore more at

Cheers! :)


Blog comments powered by Disqus