Red, green and refactor
Today I want to talk you about TDD (Test Driven Development), probably you already heard about this procedure to develop software and I hope you will have an idea about what it is.
Essentially, TDD wants you to create one or several tests while you are developing a new functionality for a particular application. The way of working with TDD always starts with the test, which needs to start failing (RED) and then we need to add the least amount of code to pass the first test (GREEN). Last step, you would need to REFACTOR your code to eliminate redundancy.
Then we would need to continue adding more failing tests, and some code to pass the tests. Essentially the process will loop over these steps: create new test / test fail / add some code / test passes.
Jasmine and Should
To do a small example I will show you how to develop a JavaScript application which implements the game: FizzBuzz. Essentially, in the FizzBuzz game, players take turns to count incrementally, replacing any number divisible by three with the word "fizz", and any number divisible by five with the word "buzz".
In order to perform the tests, we will use "jasmine" and "should" for testing javascript. I used nodejs and its npm to install both modules in my little solution. Here are some commands to install the modules once nodejs and npm were ready, you just need to place in a new folder and run:
npm install -g jasmine-node
npm install -g should
Once the modules are installed, I created a file in the root directory called kata.js where the logic of my game will be placed, a directory called spec and into this directory another file called kataSpec.js, which will contain the tests I want to perform. Note the tests files need to finish in "spec" to be processed by jasmine. In order to execute the tests you will need to run the following command:
jasmine-node spec --verbose
Now, we will start with the first test which will try to check if the method fizzBuzz() exists. Open your kataSpec.js file and write:
var Kata = require("../kata"); var should = require("should"); describe("Kata", function() { var app = new Kata.App(); it('fizzBuzz_Exists', function() { app.should.have("fizzBuzz"); }); });
At this point, we are in RED status as we don't have any method created. Note the name of our test methods (fizzBuzz_Exists) will be the description of what are we testing. Run the previous command and you will get something like this:
Now we need to move to GREEN status so let's create our first implementation for the fizzBuzz method. See the example below:
var App = function(){} App.prototype.fizzBuzz = function (n) { } exports.App = App;
Run jasmine again and you will get a green test because we have created our fizzBuzz method. The next step is do a refactor which is not needed because we just added the method and we don't have functionality in place.
Let's go for our second test method. Now we will test basic data. Let's check if our app returns zero when we send a zero to the function. This is how the test will look:
var Kata = require("../kata"); var should = require("should"); describe("Kata", function() { var app = new Kata.App(); it('fizzBuzz_Exists', function() { app.should.have("fizzBuzz"); }); it('fizzBuzz_ZeroShouldReturnZero', function() { app.fizzBuzz(0).should.equal(0); }); });
Now we are in RED status so let's move quickly to GREEN adding some code to our app: See here below how it'd look:
var App = function() {} App.prototype.fizzBuzz = function(n) { return n; } exports.App = App;
After running jasmine we should get a green status. At this stage we don't have to refactor anything because we just add the functionality to return basic data which are the first steps of our application. Now, I will add the test to check if we send the number three into our method I should get a "fizz" in return.
var Kata = require("../kata"); var should = require("should"); describe("Kata", function() { var app = new Kata.App(); it('fizzBuzz_Exists', function() { app.should.have("fizzBuzz"); }); it('fizzBuzz_ZeroShouldReturnZero', function() { app.fizzBuzz(0).should.equal(0); }); it('fizzBuzz_SimpleCase', function() { app.fizzBuzz(1).should.equal(1); }); it('fizzBuzz_IsFizz', function() { app.fizzBuzz(3).should.equal('fizz'); }); });
Running jasmine we will get a big RED for the fizzBuzz_IsFizz method, which means we need to add the least amount of code in order to pass the test. Check this out:
var App = function() {} App.prototype.fizzBuzz = function(n) { if (n === 3) { return 'fizz'; } return n; } exports.App = App;
After adding those lines of javascript we'll return fizz if we send 3 into the function and we'll echo any other value. At this point we need to REFACTOR the function to because we return numbers and one string and it doesn't represent the current purpose and use.
var App = function() {} App.prototype.fizzBuzz = function(n) { var result = n; if (n === 3) { result = 'fizz'; } return result; } exports.App = App;
Next step is create a new test to see if sending a five we get buzz.
var Kata = require("../kata"); var should = require("should"); describe("Kata", function() { var app = new Kata.App(); it('fizzBuzz_Exists', function() { app.should.have("fizzBuzz"); }); it('fizzBuzz_ZeroShouldReturnZero', function() { app.fizzBuzz(0).should.equal(0); }); it('fizzBuzz_SimpleCase', function() { app.fizzBuzz(1).should.equal(1); }); it('fizzBuzz_IsFizz', function() { app.fizzBuzz(3).should.equal('fizz'); }); it('fizzBuzz_IsBuzz', function() { app.fizzBuzz(5).should.equal('buzz'); }); });
Back to RED status, we need to get out of here! So let's add more code in our great application. See here below:
var App = function() {} App.prototype.fizzBuzz = function(n) { var result = n; if (n === 3) { result = 'fizz'; } if (n === 5) { result = 'buzz'; } return result; } exports.App = App;
At this point you have the idea of how TDD works. next steps would be add a method to check FizzBuzz together, I mean, a number which could be divided by three and five like 15 for instance. Let's add the code first to get a big red:
var Kata = require("../kata"); var should = require("should"); describe("Kata", function() { var app = new Kata.App(); it('fizzBuzz_Exists', function() { app.should.have("fizzBuzz"); }); it('fizzBuzz_ZeroShouldReturnZero', function() { app.fizzBuzz(0).should.equal(0); }); it('fizzBuzz_SimpleCase', function() { app.fizzBuzz(1).should.equal(1); }); it('fizzBuzz_IsFizz', function() { app.fizzBuzz(3).should.equal('fizz'); }); it('fizzBuzz_IsBuzz', function() { app.fizzBuzz(5).should.equal('buzz'); }); it('fizzBuzz_IsFizzBuzz', function() { app.fizzBuzz(15).should.equal('fizzBuzz'); }); });
Now it's the time to add some code in order to pass our last test. See how, following this process we are passing all the test and adding more functionality at the same time. This is really helpful for the developers due to you can't produce any gap in your algorithm. See how the code would be:
var App = function() {} App.prototype.fizzBuzz = function(n) { var result = n; if (n === 3) { result = 'fizz'; } if (n === 5) { result = 'buzz'; } if (n != 0 & amp; & amp; n % 3 === 0 & amp; & amp; n % 5 === 0) { result = 'fizzBuzz'; } return result; } exports.App = App;
Back to green, we feel safe and our code is stable and running.
Note: you probably noticed I use === instead of double = when comparing in JS. This is to compare not just the values, also the data types: What does it mean? JavaScript is not a strongly typed language, it's a prototype language and for Javascript if you compare text and numbers could be the same, ex: "2" == 2 .... Yes! But if you use three equals like here: "2" === 2 .... Mmmmm No! That's not equal because with three equals, JavaScript is checking the data type also.
I hope you got the idea and give TDD a go in your next development.
See you next posts and happy coding!
0 comments:
Post a Comment