API Design Using Behavior Driven Development
Editorial Note: I originally wrote this post for the SmartBear blog. You can check out the original here, at their site. While you’re there, take a look at some of their products in the code review, testing, and API spaces.
Test-driven development (TDD) has been around for a while now. Behavior-driven development (BDD) is a comparably recent methodology that emerged from the practice of TDD. It could reasonably be called a narrower application of TDD.
TDD is a process where one uses a failing unit test to express a shortcoming of the system. The next step is then to modify the production code to get the failing test to pass, without making existing tests fail. BDD more or less takes this same concept and adds to it the idea that the tests should be written in easy-to-understand language about the problem domain, and that they should express user acceptance criteria.
So instead of
you would have
Given a text box that has been left empty, when I click submit, I should receive an error message.
As a practice, this has found its way into the agile canon, and given rise to something conversationally termed, “three amigos.” This is a practice wherein a representative of “the business,” a tester, and a developer get together and agree on what a requested feature is, what it means, what it looks like when done, and how to verify completion. In teams practicing BDD, the output of this conversation will often be an acceptance test, expressed in the Gherkin specification language. When added to the codebase, this test will, of course, fail. The folks implementing the feature know that they’re done when they’ve succeeded in making the test pass.
If we put agile aside for a minute, this is a pretty common sense approach for any team. The essence of it is, “let’s define and be clear about what success looks like and then automate a check for it.” So you don’t need to be an agile team for this to make sense — you just need to be a team looking for clarity.
BDD in the API Provider World
Everything about BDD makes perfect sense in the line of business and traditional product development worlds. In those worlds, “the business” wants stuff from “the geeks,” and that basic operating paradigm creates the need for something like Gherkin to be necessary. As elegant as it may seem, Gherkin could easily be viewed as pidgin developer-business talk.
But what happens when you’re in the business of making products for developers?
I’ve worked with teams in the past that built a product with no user interface, to be consumed only by other software developers. For teams like this, the people on and around the team may all have software development chops. Testing is achieved through first-class programming automation. People that function as project managers or business analysts are comfortable discussing the details of a method invocation or POSTing JSON to an endpoint. The business is entirely technical, so there is no understanding deficit among the team members when talking shop.
So, BDD doesn’t apply for such teams, then, right?
Actually, I believe it does. In fact, I believe that it applies just as much to a project with technical consumers as it does to a project with business or public consumers. And the reason for this is relatively simple. While it may seem counter-intuitive, BDD isn’t ultimately about finding common ground in the language between “business people” and “geeks.” It’s about being clear about what users can expect from a system, using terms both users and developers can agree on.
To be clearer about this, let’s consider a problem domain for reselling tickets to events. If we were building a website to be consumed by the public, we might write an acceptance test something like the following to drive system behavior.
Given there are 2 tickets available for the Rolling Stones Concert When I request all tickets for the Rolling Stones Concert Then I see 2 tickets
This test would call into the presentation/controller logic of the web application. It would seed the application with 2 available tickets, make a request for all tickets, and then verify that the 2 tickets were returned.
But what if there were no website? What if the product were just a backend service for a series of resellers to use to drive their own sites? In that case, our users would be the developers at those reseller companies. In that case, why not write a test like the following?
Given there are 2 tickets available for the Rolling Stones Concert When I issue a GET to ~/concerts/RollingStonesConcert Then I receive JSON with 2 ticket entries
Most people aren’t used to Gherkin that looks like this, but this is perfectly valid. The language is intended to describe your application’s behavior in the terms of its domain. And, if your product is an API that provides this service, HTTP Verbs, JSON, resource paths, and entries are part of your domain (along with tickets and concerts).
Representing Your Users
It’s easy for us as programmers to become focused on the details of our system. What’s the performance like? What should the preconditions and invariants be for this object instance? Have we considered all the edge case scenarios for this call? And it’s doubly easy to get caught up in these sorts of details when our users are fellow programmers who would be completely empathetic.
Don’t get me wrong. The details are important — very much so. But the way users perceive and interact with your system is just as important, if not more so. BDD forces you to think about that. It forces you to form a common understanding of what success looks like with the people that are using your system. The fact that you work on a technical product isn’t a reason to pass on that opportunity — it’s a reason to double down on it.