BDD is hard to grasp, because it is more than a development methodology (unlike TDD) and there are currently very different ideas what it really means. To make matters worse there are a lot of BDD tools around that pursue quite different concepts.
In this post I try to classify two main categories among those tools.
Important for the understanding is that BDD can be practiced at different levels. At the code/unit level and at the feature level. In both cases it is a good practice to use examples to specify the behavior of the units resp. features. However in both cases we have different stakeholders and intents with the BDD process.
Both approaches to BDD are not exclusive, they can be combined.
(see also "BDD for Acceptance Tests vs. BDD for Unit Tests (or: ATDD vs. TDD)" on the SpecFlow mailing list)
Currently I would differentiate two flavors of BDD tools:
- Tools with a business readable output
- Tools with a business readable input
Tools from the second category (business readable input) try to widen the focus of the BDD process by enabling more involvement by all other stakeholders: customers, business analysts, testers maybe even operations.
This involvement is possible upfront, meaning before the developers have done their work. This business readable input is an artifact commonly owned by all stakeholders. By having a commonly owned artifact, the process tries to ensure that all involved stakeholders build up a shared understanding which is crucial for successfully software projects (for more information I suggest reading Bridging the Communication Gap by Gojko Adzic).
Because this shared understanding is input (as opposed to output) and business readable, the process can even be taken further and make the artifact business writable. If this is achieved successfully then we have done a big step towards executable specifications.
In practice we often see tools of the first category (business readable input) used as a replacement/extension for TDD at a unit-testing level.
In this case the behavior of the unit under development is focused by trying to specify this behavior upfront in a less technical way. However this is usually not interesting for other stakeholders than developers, because the technical units under development are usually too fine grained and have no meaning to non technical persons. Also technical units are the primary focus of developers and they are the main stakeholders (think of testability, separation of concern, maintainability ...), other stakeholders should not be too involved here. So this is mainly a tool for developers and allows in some cases the mapping of technical units to overlying features.
The second kind of tools aim clearly at Acceptance Testing and Acceptance Test Driven Development. Here system features are clearly focused. Features are usually more coarse grained than the behaviors of single technical units. Features should always be understood and driven by business requirements.
It is certainly possible to write acceptance tests with the first category of tools, but the driving aspect (as in Acceptance Test Driven Developement) is certainly harder to achieve and less supported by these kind of tools.
Examples:
Easyb is a Groovy based tool of the first category. The following example (from this post) shows how behavior is specified at at unit-level (class-level):
scenario "Two amounts with the same currencies are added", { given "Two different amounts with the same currencies", { money1 = new Money(12, "CHF") money2 = new Money(14, "CHF") expected = new Money(26, "CHF") } when "Add given amounts" , { result = money1.add(money2) } then "New amount is sum of two given ones", { result.equals(expected).shouldBe true
} }
scenario "Two amounts with different currencies are added", { given "Two amounts with different currencies", { money1 = new Money(12, "CHF") money2 = new Money(14, "EURO") } when "Add given amounts", { add = { money1.add(money2) } } then "Operation should fail", { ensureThrows(IllegalArgumentException) { add() } } }
Executing the above story gives you the follwowing readable report:
2 scenarios executed successfully.
Story: money
scenario Two amounts with the same currencies are added
given Two different amounts with the same currencies
when Add given amounts
then New amount is sum of two given ones
scenario Two amounts with different currencies are added
given Two amounts with different currencies
when Add given amounts
then Operation should fail
Cucumber is a tool of the second category. The following example from cuke4duke shows how an executable feature is specified:
Feature: Book search
In order to find books I might buy
As a potential customer
I want to search for books by different criterias
Background:
Given the following books
| Author | Title | Year | Publisher |
| Martin Fowler | Patterns of Enterprise Application Architecture | 2002 | Addison Wesley |
| Eric Evans | Domain Driven Design | 2003 | Addison Wesley |
| Gerard Meszaros | xUnit Test Patterns | 2007 | Addison Wesley |
Scenario: Search for title
When I search for title 'Patterns'
Then the result list should contain 2 books
Scenario: Search for author
When I search for author 'Fowler'
Then the result list should contain 2 books
When executing this example (using cuke4duke) the whole EJB stack is exercised, including database-access. The result is the following report:
(of course Cucumber can generate a lot of different outputs)
History (as I could reconstruct it):
Tools from the first category evolved from TDD. Dan North introduced BDD in 2002, see his introductory blog post.
JBehave was one of the first BDD tools, at this point clearly part of the first of the above categories.
Then the BDD movement was mainly driven by the Ruby/Rails community. RBehave was introduced and then merged into RSpec as RSpec Story Runner.
RSpec then was as a tool that could satisfy both of the above catgories
RSpec StoryRunner was then dropped and Cucumber was created. Cucumber coined the current flavor of BDD tools with plain-text specifications. Cucumber also is aiming at extending its reach beyond Ruby/Rails (see cuke4duke, cuke4Nuke, gherkin).
Other first-generation tools then adapted and also support plain-text specifications (JBehave2, NBehave).
Beside all those explicit BDD tools there is FIT/FitNesse. FIT was also invented in 2002 by Ward Cunningham. Its goal was enabling collaboration and communication through automated accepatance testing. FitNesse took up the basics of FIT and provided an intuitive, wiki-based frontend/IDE.
While FIT seems to have practically died, FitNesse is still thriving. FitNesse also recently added Parameterized Scenario Tables and there is GivWenZen. This makes it possible to use the plain-text GWT (Given-When-Then) syntax, that was made popular by the plain-text BDD tools.
I will list a more complete overview of BDD tools for the Java and .Net platforms in later posts.
Great post Jonas!
ReplyDeleteThat clarified some confusion for me...
I find your reference to "business readable input" interesting.
ReplyDeleteWhile it's a business readable input in the sense its the input to development its focus is on describing the systems output (and hence its value).
Feels like that fundamental focus is missed in just referring to it as an input.
It's a business readable specification of the value of a feature which forms the input to development.
Hi Joseph,
ReplyDeleteof course you are right.
I somehow presumed that it goes without saying, that the goal of BDD and specification by example is to describe features (on unit or on system level) and to drive the development of those.
This goal is the same for both classes of bdd tools.
The difference in my experience is that on unit level usually the plain text specs are formulated by the developers only, and this makes sense.
On the feature level it is possible and the goal that the plain text specs are formulated by all stakeholders including the business.
Plain text specs on feature level go hand in hand with user stories.
With plain text specs it is possible to formulate acceptance criterias to user stories at the right time (just before the story is implemented) with the right level of details (sufficient formality).
Great Post! I didn't found a better explanation on this particular topic on any other site. I expect to see some more post that will clear my points in Unit Testing.
ReplyDelete