Cucumber is a tool that supports Behaviour Driven Development, BDD. A lot of people think that the only place where a system has behaviour is in the user interface and especially in the graphical user interface. As a developer I know that this is not the case. All systems have behaviour at different places and different levels.
I will show an example of how a system can be developed using its desired behaviour and start from a non graphical point. I will work from the model down to the database and when I’m happy with the logical behaviour I will add a graphical user interface on top of it. I will actually add a few different interfaces; two web-based, one swing and two different types of web services. The result will be an example of Model View Controller, MVC, developed using BDD.
An important point when I add the GUIs or web services is that I will not change the desired behaviour. I will only change how the behaviour is verified. This is one way of showing you that Cucumber and BDD is not about testing GUIs. It is about systems behaviour.
Table of content
- BDD should be declarative
- The Example
- Building the model
- A JSF web application
- A Wicket web application
- Building a Swing GUI
- A RESTFul web service
- A SOAP web service
A lot of developers think of tests as unit tests. Tests written using tools like JUnit are almost always imperative. This is of course due to the language the tests are being written in. Java is an object oriented and imperative language. It is therefore natural that the tests will be imperative.
If you specify properties you want a system to have, then you will be using a declarative paradigm instead.
BDD and Cucumber should be used declarative. You define properties that should hold true for a solution. A set of boundaries the solution should stay within. You don’t know, and should not care, about the implementation when you define your features. The implementation comes later and is an S.E.P. or ‘Somebody Else’s Problem’. You might be somebody else, but then you act in a different role that you would like to separate from the role that defines the wish list (requirements) for the system.
This is similar to SQL (which is an implementation of Relational Calculus and Tuple Calculus). You define properties that you expect the answer to have and don’t really care about how it is calculated. You might care if you are trying to apply some optimization, but that’s an implementation detail and really not important for the proper functionality.
Finding good examples that show the problem you want to highlight without being trivial is difficult. Understanding the large picture may be hard if there are too many details. Another problem one faces when writing a tutorial is to use either too large or too small steps. If you take too large steps without explanations, then people will have problems following your ideas. Too small steps tend to be boring and readers may feel that you assume that they are stupid. Finding the right balance is crucial and really difficult.
I have used an example of fuelling a car in previous examples. I could reuse it, but I have decided that a car rental system would be more fun. It is the same thing from a tool perspective. Things are created, located, updated, and removed. The important thing to understand is that the example, or the model used in the example, is not important. It is just at tool for describing the ideas.
In a car hiring system you would expect to be able to
- Search for cars to rent
- Rent a car
- Return a car
- Charge rent for a car
- Maintain an inventory of cars
The most valuable feature for the company that uses a system like this might be the possibility to have its customers renting cars. This is how they making there living.
Some infrastructure is needed so cars can be rented. The cars have to be created in the system, it must be possible to calculate a price for renting a car and similar. This list could be very long. I will start with perhaps the most important feature; find and rent a car. If I can deliver this feature early, real world users can try it out and give me feedback if I am missing something important.
This is actually the only feature I will implement. It will be implemented in such a way that I hope you are able to understand how it is done and understand how the example can be expanded for the second most important feature, without breaking the first feature.
I will use Model View Controller, MVC, strict. The model will be developed first and it will never change when the view is changed. The reason for this is simple; the desired behaviour is implemented in the model. Since this is the behaviour we want, we don’t have any valid reason to change it just because an interface is added.