Thursday, March 27, 2008

BDD in JavaScript

BDD is a way of building applications in a question-answer-test way. Before you build some part of the application, you make a set of questions, then you answer them and make tests which the code should pass. The tests are made to satisfy the answers. A simple, probably often used example: assume you are making a calculator. One of its operations is addition. You ask: "What should 2 + 3 be?", then you answer "5" and you write a test that, when executes, checks your code with the given inputs (2 and 3) and the expected output (5).

In JavaScript, you can use JSSpec (or JSSpec) framework to do your BDD. Let's say you have written the following function to represent the wanted addition:

function addition(a, b) {
return a + b;
}

Here is the BDD description of the test mentioned above:
describe('Addition', {
'2 + 3 = 5': function() {
expect(addition(2, 3)).should_be(5);
}
});

Download the file containing this simple test from here.

This is the basis of BDD. The basic pattern is:
  • Take a problem that needs to be solved next
  • Make a set of questions about the problem
  • Answer the questions
  • Make a BDD description out of the answers
  • Make the code
  • Test the code using the BDD description
  • Fix the code until the test passes successfully
It is common to make one test per class or module, depending what you are testing. You should cover everything in a class, that is test every non-private method in a class. You can test even private methods, but a good rule of thumb is that if you need to test private methods, then they probably belong to some other class. The sole need to test private methods means they are important. Everything that is important needs to be tested. Play by ear here. Often you have private methods that are only utility methods - extracted parts of other methods to simplify the code.

Try to test small pieces of code (for example, at least one test per method is a good thing) and to test everything, especially the corner cases. The above is written assuming you are using JSSpec to test your code. Take a look at their Wiki for more details - although, at the time of this writing, the documentation is still unfinished and rather sparse. The basics are covered well, however, so you won't have too much trouble if you are not pushing the limits.

The above example is not very exciting by itself. I will make another one, which incorporates the description for the class I am going to use in the near future. The class is called Model. It will probably be clearer why it's used in the next post - it is the part of the MVP pattern. For now, I will give only the simplified view of this class. This is a good thing anyway - BDD should be used in a minimalistic way, in my opinion (you might say this is YAGNI).

Say we need the class to represent some data in our application. For example, if application is dealing with issuing airline tickets, you might need information like how many airplanes you have, how many passengers fit into the airplanes, how many flights you have planned for some day and at which times, etc. Being a good OO, you should find out all the objects that are interesting to your application (e.g. airplane, ticket, passenger, ...). It will probably happen that you will display information about many (if not all) of these.

MVP suggests that these classes be separated into the M part - the Model part. This way you will have the option to subscribe to the notifications from them when some of their properties change. For example, if you have the Airplane class representing the airplane and it has a numberOfPassengers property, you can subscribe to the notifications about the changes of this property. This allows you to, for example, forbid booking any more tickets for that flight if the number of passengers equals to the number of seats in that airplane.

It would be daunting, however, to have to write the boilerplate code that does the notifications for each of the classes. It is quite normal for the model classes to be rather short and many times they only represent the data. This is very similar to Java beans. The only difference is, in fact, that they should have the Observer pattern implanted into them. This pattern is very simple to factor into the parent class - the Model class I mentioned above.

How would we develop this class using BDD? The problem definition is quite easy in this case. What we need to define is based on a black-box way of thinking. Essentially, you define how the instances of this class will behave from the outside. This is how BDD is implemented. For our Model class, we need a class that will:
  • Allow the set of properties be defined (which will be subject to observation),
  • Allow others to subscribe or unsubscribe to the notifications about the changes on any property of the class,
  • Notify every observer of the current state of the instance.
The above is the basis for our BDD test suite. Here is a very short Model BDD description:
describe('Model', {
before_all: function() {
// Sample class inheriting from Model we are going to test.
MyModel = function() {
Model.call(this);
}
Klass.extend(MyModel, Model);
Model.addProperty(MyModel, 'number');
Model.addProperty(MyModel, 'color', {liftSet: true});

model = new MyModel();
model.setColor = function(newValue) {
this._setColor('Color is ' + newValue);
}
},

'Properties should work': function() {
model.setNumber(11);
expect(model.getNumber()).should_be(11);

model.setColor('green');
expect(model.getColor()).should_be('Color is green');
},

'Should notify observers properly': function() {
var fired = false;
var mockObserver = {
numberChanged: function() {
fired = true;
}
};
model.addObserver(mockObserver);
model.setNumber(55);
expect(fired).should_be(true);

fired = false;
model.removeObserver(mockObserver);
model.setNumber(44);
expect(fired).should_be(false);
}
});

It starts with the standard BDD 'describe', which says it describes 'Model' with the three methods object. The first method - before_all - it the method that will be executed when BDD testing starts, once and before all the real tests (i.e. before the other two methods). In before_all, there is a definition of the sample class called MyModel, which inherits from Model. MyModel has two properties: number and color. You can see that color property has the setter overridden, which will do something irregular (i.e. it's not the standard setter that only sets the property, but does more work).

The actual BDD tests follow. These tests have their names: 'Properties should work' and 'Should notify observers properly'. The names should be as descriptive as possible about what this part of BDD description actually tests. It should be the part of the business definition of our Model - the three-item list before the code. As you can see 'Properties should work' describes the first item - allow the properties to be defined. 'Should notify observers properly', on the other hand, combines the second and the third item - allow observers to be added/removed and acutally notify them.

In BDD, this is the first step. We have a description that we can automatically run and test whether the class that we write is what we wanted. If the tests pass, we are good. If they fail, the class is not good. It must be noted that the BDD description can change if the requirements change, which is quite usual when you are agile. However, you should always follow "write tests, then write class" order.

The above description also is YAGNI. Let me give you an example. If you need to go to the grocery store (this seems like a simple and common problem to take as an example), you have many options:
  • Walk,
  • Take a bike,
  • Take a train or a bus,
  • Drive in a car,
  • Use a helicopter.
Any of the above options are possible and quite reasonable in different situations. If you don't have a bike, train, car or a helicopter (and you don't want to die of starvation), you would walk. The next three options are mostly a matter of preference (if they are available). If the grocery store is on the island, a helicopter might be the best option. The important thing is - even if you had a helicopter, you probably wouldn't fly if the store is a block away...

The same is with writing the code. To satisfy the above BDD description, you can write the very simple Model class or you can write a 10K lines monster. The question is - do you need a 10K monster? No. If you did, the BDD description would include everything in there, because BDD description should include everything you need. Simply put - if it's not in BDD, then either don't build it (YAGNI) or amend the BDD description to include the missing thing(s).

At the end - how would you run the above BDD spec? Go to JSSpec User Guide. There is a "Define new specification" part. Replace the text: "// Your spec goes here" with the above description and that is it. In fact, it is not - you need to write the class (Model) and include it (in the normal way JavaScript files are included - using script tag). I will give the example Model implementation in my post about MVP in JavaScript.

No comments: