Stories about Software


Getting Started with Behavior-Driven Development

Editorial note: I originally wrote this post for the TechTown blog.  You can check it out here, at their site.  While you’re there, have a look around at the different training courses they offer.

You’ve probably heard of behavior-driven development (BDD).  However, if you’ve never practiced it, you may perceive it as one of many in a nebulous cloud of acronyms.  We have BDD, TDD, DDD, and ATDD.  All of these have a “D” standing for “driven” and another one standing for either “development” or “design.”  Apparently, we software developers really like things to drive us.

I won’t engage in a full “DD” taxonomy here, as this post concerns itself with behavior-driven development only.  But we will need to take a tour through one of these in order to understand BDD’s motivations and backstory.

Behavior-Driven Development Origins and Motivation

To understand BDD, we must first understand test-driven development (TDD).  Luckily, I wrote a recent primer on that.  To recap briefly, TDD calls for you to address every new thing you want your production code to do by first writing a failing test.  Doing this both verifies that the system currently lacks the needed functionality and gives you a way to later know that you’ve successfully implemented it.

With TDD, you deal in microtests.  These distinguish themselves by being quite specific and granular.  For instance, you might assert that you get a null reference exception when invoking a method with a null parameter.  You’ll pardon non-technical project stakeholders for a distinct lack of interest in these microtests.

BDD evolved from asking the question, “Why don’t we do this for tests that the business might care about?”  It follows the same philosophical approach and logic.  But instead of worrying about null parameters and exceptions, these tests address the system’s behavior at the capability or feature level.

Behavior-driven development follows the TDD cadence: express a current system deficiency with a failing test. But this time the failing test is, for example, when I deposit money into my checking account, I can see the reflected balance.  Work then proceeds on that feature until the test passes.  At this time, the team considers the card complete.

Speaking the Language of the Business

The first thing you probably find yourself wondering is how this works from a nuts and bolts perspective.  Sure, it makes for a great concept.  But how exactly do you translate businesspeople’s English into code?  Enter a clever construct called Gherkin.

Gherkin operates via a simple but clever premise—restrict English to a very narrow, and thus parsable, subset.  Let’s look at an example.

This won’t exactly win a Pulitzer Prize, but programmers and business folks alike can easily read and understand it.  And for this compromise in eloquence, you get the kind of pattern that makes programming languages work.  “Given,” “when,” and “then” all represent meaningful language keywords.  A framework uses these to map the statements that come next to methods in source code.

And Then Translating Business Language to Code

To understand how that works, consider some C# code.  This represents a relatively concrete example of mapping the statement following the given keyword to some actual, executable code in your codebase.

The first line of code contains a C# attribute (equivalent to a Java annotation, for you Java folks).  This attribute links the English text to the method in question.  As you can see, it also uses an escaped variable to translate the number 100 into a variable for the method.

From there, you have it pretty easy.  The “given” stipulates a checking account balance of $100.  So you oblige in the code of your domain by creating a checking account with a $100 balance.  You would follow suit for implementations of the “when” and “then” keywords as well.  All of these combine to translate simple English into tests in your code.  And your BDD framework will have enough smarts to execute the methods in the proper order.

Now I should mention at this point that things aren’t quite this simple.  You will need to manage some class-level state between invocations of these methods.  In other words, in the method above, I declare a variable with only method scope.  Obviously, you couldn’t do anything useful with that in the “when” and “then” methods.  I’m just using this oversimplified code to demonstrate the business-language-to-code mapping.

Collaborating with Business Stakeholders

Now that you understand how this works conceptually, we can revisit how you approach this development paradigm.  With TDD, you write a failing test, make it pass, and then refactor, all the while keeping all remaining tests green and passing.  What kind of cadence do you adopt with BDD?

To understand that, think beyond the development team.  This approach fits in pretty seamlessly with Scrum and its roles and stakeholders.  For example, imagine a product backlog filled with user stories.  Working with the product owner and any necessary analysts, you can pretty easily express a user story as one or more Gherkin scenarios.  A so-called three amigos collaboration between BAs, developers, and testers can result in the writing of failing Gherkin scenarios.

The development team then gets them to pass.  After that, the QA team verifies their passing, and the product owner or business stakeholders signify their acceptance of the effort.

As for the development team’s cadence with the scenarios, that also becomes simple.  You have a backlog that prioritizes scenarios (stories) by business value.  The team picks one up, expresses it with a red behavior/test, and gets that test to pass without breaking others.  It echoes the TDD cadence.

The BDD/TDD Cycle

That brings up the obvious question of how to practice BDD and TDD simultaneously.  People often wonder about this after receiving an introduction to the topic, and understandably so.

To clear the muddied waters, consider that these two practices occur at different levels of granularity.  BDD operates at the granularity of features and components, whereas TDD operates at the granularity of methods.  When you implement a feature in your codebase, you usually add or modify many different methods and classes.  This means that TDD practitioners write many different microtests during feature development.

This idea translates naturally to the BDD/TDD cycle, as illustrated by the diagram in this post.  You write a failing acceptance test/behavior first.  You then enter into your TDD cycle, working on the feature with your normal red-green-refactor cadence.  After some number of those cycles, you’ll finish the feature/behavior, resulting in a green acceptance test.

Getting Started on Your Tech Stack

While I used an example in C# earlier, I could have picked pretty much any language.  I have this flexibility because of the language-agnostic nature of Gherkin.  Quite simply, you can use Gherkin in just about any tech stack you please.

All you need is a framework for wiring the Gherkin to the tests in your language.  If one doesn’t exist, you could always write one, but plenty of them exist.  This post contains an impressive breakdown of your options, organized by tech stack.  As you can see, you have plenty of options with major programming languages.

From here, your best bet is to pick one, install it, and try it out.  I can speak from experience in saying that experimentation is your quickest path to getting comfortable.  By no means have you completed your learning on the subject, but hopefully things have been demystified enough for you that you’re ready to try it out for yourself.