We talked about test-driven development. We considered it the basis for Behavior-driven development. But what’s the difference between them?
Test-driven development focuses on the developer’s opinion on how parts of the software should work. Behavior-driven development focuses on the users’ opinion on how they want your application to behave.
Test-driven development is rather a paradigm than a process. It describes the cycle of writing a test first, and application code afterwards – followed by an optional refactoring. But it doesn’t make any statements about
- Where do I begin to develop?
- What exactly should I test?
- How should tests be structured and named?
The name test-driven development also caused confusion. How can you test something that’s not there yet?
It was Dan North 1 who noticed all these unsolved questions and came up with a solution: He suggested that instead of writing tests you should think of specifying behavior. Behavior is how the user wants the application to behave.
When your development is Behavior-driven, you always start with the piece of functionality that’s most important to your user. I consider this phase as taking the developer hat off and putting the user hat on. Once you’ve specified the user needs, you put the developer hat back on and implement your specification.
In my experience, this is the hardest part of the process: Often you don’t know what’s the most important Behavior for your user. However, over time and with a lot of feedback it becomes more apparent. But we’ll get into that in a later blog post.
For now, let’s assume we know what’s most important to our users. So we know where to get started, but how do we specify Behavior? In traditional unit testing frameworks like Test::Unit a test would look like this:
class UserTest < Test::Unit::TestCase def test_name_set user = User.new "Audrey" assert_equal(user.name, "Audrey") end end
This certainly works, but there are some flaws:
- There’s the word test in the class name and the method name, but we’d like to specify requirements instead.
- The syntax is understandable but still appears artificial.
- And most importantly: The test name doesn’t state what it really tests.
In Behavior-driven development you specify Behavior in whole sentences. Not just the naming but also the code syntax should read naturally:
describe User do it "lets me assign a name" do user = User.new "Paul" user.name.should == "Paul" end end
Now we know that a user lets you assign a name. But what’s the real value of this syntax?
- Focus: You test exactly what the sentence says. No more, no less. This will let you write fine-grained and expressive specifications.
- Documentation: Just by reading the sentence, your team-mates will understand what this Behavior is about. They don’t need to read a single line of code.
- Regression: When you run all these specifications later on, they become regression tests. When a regression test fails, you immediately see what Behavior of your application is broken.
But while this syntax is useful for specifying fine-grained Behavior of your application’s components, it still doesn’t say anything about the intentions of your users.
Dan North suggested a template that lets you describe features in natural language:
Story: Returns go to stock In order to keep track of stock As a store owner I want to add items back to stock when they're returned
Scenario 1: Refunded items should be returned to stock Given a customer previously bought a black sweater from me And I currently have three black sweaters left in stock When he returns the sweater for a refund Then I should have four black sweaters in stock
Scenario 2: Replaced items should be returned to stock Given that a customer buys a blue garment And I have two blue garments in stock And three black garments in stock. When he returns the garment for a replacement in black, Then I should have three blue garments in stock And two black garments in stock
Each story has a title and a short description of what the story is about. The format of this description is always the same:
- In order to get some benefit
- As the user you are developing for
- I want what this feature does
This description is always followed by a list of scenarios containing
Given steps (what has happened before),
When steps (what actions the user performs), and
Then steps (the desired outcome for the user).
Here, we also apply the principle: Start with the Behavior that’s most important to the user.
- Find out the feature that’s most important.
- Within the feature always select the most important scenario.
This way you always stay aligned with your user’s needs and focus on the stuff that matters.
There are tools like Cucumber that enable you to test your natural language features automatically.
Many people refer to Behavior-driven development as “test-driven development done right” 3. In fact, Behavior-driven development is a set of best practices that advise you on how to develop software by centering your users.
In the past software development was mainly about technical solutions. This has changed! Behavior-driven development focuses on the purpose of your work to people who will use it. This way you will create better software and successfully address your customers’ needs. The technical solution arises from this process almost by itself.
In the next few episodes of Testing Tuesday I will introduce a few tools for Behavior-driven development. Stay tuned!
I barely scratched the surface of Behavior-driven development here, so I especially recommend checking out the references and further info (see below).
- The Codeship
-  Dan North’s original blog post
-  Wikipedia: Behavior-driven development
-  Get Your TDD Right with BDD Further info:
- YouTube video: BDD vs TDD (explained)
- The RSpec Book: Behaviour-Driven Development with RSpec, Cucumber, and Friends