Friday, 22 February 2013

BDD and Automated Acceptance Testing for Java Web Apps: A Primer

Behavior Driven Development (BDD) is an approach in which we build up our understanding of user requirements using concrete examples of the application's expected behavior. Through ongoing conversations between business stakeholders and team members, we explore the capabilities and behavior that the stakeholders need. We propose features that the system will need to deliver these capabilities, and use concrete examples and counter-examples to explore and understand these features more fully.

In BDD, requirements are expressed using language understood both by the business stakeholders and by the development team, and in a semi-structured format that can act as the basis for automated acceptance criteria. Requirements are generally expressed using a structured form along the following lines:

In order to obtain some business value
As a stakeholder
I want a feature
Examples are also expressed in a structured way:
Given some initial context
When some event occurs
Then some outcome should occur
These examples form the basis for the acceptance criteria that validate the features we deliver. They help ensure that the requirements are both well understood and testable. And they act as a starting point and a target for development work, helping developers write more focused, higher quality code that provides real business value.

Discovering these acceptance criteria is in itself a powerful learning process, but automating them makes them an order of magnitude more useful. Automated acceptance criteria provide excellent feedback on the status of a project, help document and structure the requirements of your application, and provide a sort of "living documentation" for your system. And, almost incidentally, they also provide a nice set of regression tests.

In this article, we will take a short guided tour of automated acceptance testing for a web application using JBehave, Thucydides and Selenium 2/Webdriver. JBehave is a Java-based BDD framework similar to Cucumber, that helps define requirements in plain English terms easily understood by business stakeholders. And Thucydides is a library that helps organize and report on your acceptance tests, and provides strong integration with Selenium 2/Webdriver tests.

Discovering the Requirements

During the rest of this article we will be working with a simple online dictionary project, learning how we can document and automate a set of acceptance criteria for this application. Before we get into the code, though, let's take a step back and consider how we get these requirements in the first place.

Goals and Capabilities

A good way to start a discussion about requirements is to think about the business goals of an application. Most real application goals involve money in some form (increasing or protecting revenue, decreasing costs, and so forth). This application, on the other hand, is a public service: the main goal of the dictionary is to educate online readers. We could express this more formally like this:
Goal: Educate online readers
In order to increase the general knowledge of the internet community
As a benevolent service provider
I want to enable internet users to improve their vocabulary
Taking this discussion further, we would discover what capabilities we need to deliver this goal. The most obvious capability might be the ability to discover what a word means:
Capability: Teach internet users the meaning of new words
In order to improve the vocabulary of internet users
As a benevolent service provider
I want internet users to be able to discover the definitions of words they do not know
During our discussions with the users, other related capabilities will emerge. For example, we will need to be able to maintain dictionary definitions:
Capability: Update definition
In order to keep the dictionary definitions up to date and accurate
As the dictionary maintainer
I want to be able to update definitions in the dictionary
Features, Stories and Scenarios

Of course, capabilities are a little too high-level to be directly useful when building our solution. To deliver capabilities, we need features. For example, one feature for this application could be the ability to look up the definition of a particular word. In good BDD style, we could express this using a concrete example, as illustrated here:
Feature: Lookup definitions
In order to understand what I am reading about
As a reader
I want to be able to look up definitions of words

Scenario: Looking up the definition of a word
Given the user does not know the meaning of the word 'banana'
When the user looks up the definition of the word 'banana'
Then they should obtain a definition containing the words 'An elongated curved fruit'
Note that the vocabulary and organization of the requirements may vary from project to project, and from team to team. For example, for more complex requirements, it is often convenient to split these features into stories before detailing the examples.

This is of course a very simple example. Examples like this not only clarify our understanding of the problem; they also help flush out counter-examples and corner cases. For example, suppose that while we are discussing this example with the users, one of the users asks about spelling mistakes: if a user enters an incorrectly spelt word, should the application simply reject it or propose a similar valid word? After discussion, we come up with the following example:
Scenario: Looking up the definition of a word containing a spelling mistake
And the user does not know how to spell
When the user looks up the definition of the word 'bananna'
Then the application should say 'did you mean: banana?'
We could also generalize this requirement by providing several different examples, in tabular form, e.g.
Scenario: Looking up the definition of a word
Given the user does not know the meaning of the word word
When the user looks up the definition of the word word
Then they should obtain a definition containing the words definition
| word              | definition                                                      |
| apple             | A common, round fruit                                |
| banana         | An elongated curved fruit                           |
| pear               | An edible fruit produced by the pear tree|
Of course, a capability typically requires more than one feature, another feature that could help deliver this capability, especially in the context of the original business goal, might be the following:
Learn the meaning of a new word every day
In order to improve my vocabulary
As an online reader
I want to regularly learn the meaning of new words
However, we may well decide that this feature is not as important as the first, and therefore put off elaborating it until later on. Indeed, not all features are equal, and it is important to consider their relative business value when deciding which features to implement first.

Related Posts