From Test Driven Development to Behavioral Driven Design
by Terry Mork
December 2014
Test-driven development (TDD) is a software development principle and practice – a way of developing valuable software. Test-driven development is closely tied to the test-first programming method of eXtreme Programming (XP). Kent Beck rediscovered and popularized this practice in his book "Test Driven Development by Example."[1]
In his book, Beck illustrates the development cycle as:
- Add a test
- Run all tests and see if the new one fails
- Write some code
- Run tests
- Refactor code
- Repeat
Each feature begins as a test. To write such a test, the developer must understand the requirements and specifications of the feature. The developer then executes all the tests to ensure the newest one fails. Otherwise, the new code will likely be worthless. The next step is to create code to make the test pass. One critical piece that Beck eludes to but doesn't call out specifically is that after the code has been refactored, the tests should be run again. Then once all tests pass, then the developer knows the new code meets the test criteria. An evolving code base must be refactored, or cleaned up, regularly. The cycle continues as the functionality evolves.
In more simple terms, TDD can be explained as Red, Green, Clean.
- Red - write a failing test
- Green - make the test pass
- Clean - clean up or refactor your code
There are many advantages to TDD. It enables developers to take small steps when writing software. It is far more productive than attempting to code in large steps. For example, assume you add some new functional code, compile, and test it. Chances are pretty good that your tests will be broken by defects that exist in the new code. It is much easier to find and then fix those defects if you've written two new lines of code than two thousand lines. Lastly, testing early and often (finding and fixing) is much less costly than finding and fixing later in the development lifecycle.
Behavioral-Driven Development
So let's take it one step further with behavioral-driven development (BDD). While TDD focuses on the developer's point of view on how the feature should work, BDD focuses on the user's perspective on how the feature should behave. Thus, BDD is an evolution of TDD.
Behavioral-driven development was introduced by Dan North with issues he continually came across in test-driven development.(2) He suggested that instead of simply writing tests, developers should think of specifying behaviors, which is how the users want the feature to behave. In BDD, you should always start with the features that are most important to the users. Through collaboration and continual feedback, the practice of knowing what is most important becomes clearer.
To accomplish this, BDD focuses on how a desired behavior should be specified. Implying that the desired behavior has business value. Thus, it is critical to specify this business value, which has now become the standard for documenting user requirements (stories):
As a (role)...
I want (activity)...
So that (business value)...
In the past, we were focused on who the feature was being developed for and what function they were performing. However, a critical piece was missing; why does this user want to perform this function. If we don't know why, then do we really need that feature?
While, there are no formal requirements for documenting these user stories for BDD, Dan North suggested the Given/When/Then format of expressing various scenarios, called acceptance criteria. Similar to the format of a user story, the acceptance criteria has purpose:
Given (that this setup is in place)
When (this action occurs)
Then (these are the expected results).
Given is the state of the application before the test, which may be multiple statements about this state. When represents the programmatic action under test or changes to the application. And finally, Then references the state after the test. The scenarios are written in business terms with no reference to the UI through which the actions occur. The scenarios should cover positive (happy path), negative and edge cases.
GWT Examples
Below is a very simplistic feature that we can all relate to and its associated scenarios:
Story: Network logon password.
As an Acme employee
I want to log on to the corporate network with my user ID and password
So that I can perform my job effectively.
Story Detail:
- Password must be between 6 and 15 characters
- Password must contain at least 1 upper case letter
- Password must contain at least 1 lower case letter
- Password must contain at least 1 number
- Password must not contain any special characters
Scenario 1: Enters valid password
Given the ID "E123456" exists in the system
And the ID has logged into the system before
When the user enters "Abcd123"
Then the password succeeds
And the user is logged into the network.
Scenario 2: Password with less than minimum characters
Given the ID "E123456" exists in the system
And the ID has logged into the system before
When the user enters "Ab123"
Then the password fails
And an error message is presented
And the user is directed to attempt to log in again.
Scenario 3: Password with greater than maximum characters
Given the ID "E123456" exists in the system
And the ID has logged into the system before
When the user enters "ABCDEFG123456789" the password fails
And an error message is presented
And the user is directed to attempt to log in again.
Scenario 4: Password with no lower case
Given the ID "E123456" exists in the system
And the ID has logged into the system before
When the user enters "ABCD123"
Then the password fails
And an error message is presented
And the user is directed to attempt to log in again.
Scenario 5: Password with no upper case
Given the ID "E123456" exists in the system
And the ID has logged into the system before
When the user enters "abcd123"
Then the password fails
And an error message is presented
And the user is directed to attempt to log in again.
Scenario 6: Password with no numerals
Given the ID "E123456" exists in the system
And the ID has logged into the system before
When the user enters "ABCDefg"
Then the password fails
And an error message is presented
And the user is directed to attempt to log in again.
Scenario 7: Password with special character
Given the ID "E123456" exists in the system
And the ID has logged into the system before
When the user enters "Abcd12?"
Then the password fails
And an error message is presented
And the user is directed to attempt to log in again.
Scenario 8: Password with "space"
Given the ID "E123456" exists in the system
And the ID has logged into the system before
When the user enters "Abc 123"
Then the password fails
And an error message is presented
And the user is directed to attempt to log in again.
Scenario 9: Password with all spaces
Given the ID "E123456" exists in the system
And the ID has logged into the system before
When the user enters spaces
Then the password fails
And an error message is presented
And the user is directed to attempt to log in again.
Scenario 10: Null password
Given the ID "E123456" exists in the system
And the ID has logged into the system before
When the user enters a null
Then the password fails
And an error message is presented
And the user is directed to attempt to log in again.
While this may seem like a lot of scenarios or test cases, the possibilities of the business rules stated above are almost unlimited. With these 10 simple scenarios, we can be assured the code and behaviors are correct when all 10 pass.
This format is referred to as the Gherkin language, which has a syntax similar to the above example. The term Gherkin is specific to the Cucumber and jBehave software tools.(4)
While there are those who believe BDD is TDD done correctly, it is based on a set of best practices focused on the users. With BDD, there is a paradigm shift from thinking that software development is all about the technical solutions, to focusing on the purpose of the software to those actually using it.
So why do this at all? As previously mentioned, BDD shifts the thinking from the developer's point of view to that of the users of the system. However, that is not a reason for doing so. I will answer that question initially with another question. What enables us to be agile, to deliver software in small increments, to continually incorporate feedback, to refactor with every increment?
Agility = Automated tests that run on demand
Expressing test scenarios in the above-mentioned format and within the construct of BDD, will greatly increase the ability to automate tests. While there will always be testing that cannot be automated such as exploratory testing, it will increase productivity, reduce risk, and increase overall quality of the software being developed.
Summary
This is just the tip of the iceberg in regards to both TDD and BDD. For more information on this subject, you can review Dan North's and the jBehave websites.
References
- [1] Beck, Kent. Test Driven Development by Example, Addison Wesley - Vaseem, 2003.
- [2] North, Dan. "Introducing BDD." 2006.
http://dannorth.net/introducing-bdd/ - [3] North, Dan. "What's in a Story?" February, 2007.
http://dannorth.net/whats-in-a-story/ - [4] jBehave
http://jbehave.org/
Software Engineering Tech Trends (SETT) is a regular publication featuring emerging trends in software engineering.