Installment three of "Relishing Perfection", a series on doing BDD with Cucumber, "the right way". If you are new to this series, I recommend you start with
the introduction.
Writing Cucumber Features
The first step is projecting the general set of requirements into a set of User Stories. In the BDD world fueled by Cucumber, a Feature embodies the bulk of what a User Story is. This work is the essential analysis of the Business Analyst role: distilling hopes, wishes, a nebulous dreams into concrete, actionable goals. The practice of the actual analyst is a topic for another discussion; in this line of thinking, we are going to focus on the actual articulation of user stories (as Cucumber Features) and how that articulation is affected by the fact that Features are executable. The following are some guidelines and specific practices to help guide the authoring portion of this effort.
An Appropriate Nod to Dan North
Dan North, the gentleman who coined the term Behavior-Driven Development, has just posted an excellent and more rigorously minded model for looking at the very topic of choosing the right phrasing for Cucumber Features. You will do yourself right by studying his insightful blog entry
Whose domain is it anyway?. The short short is to minimize the number of domains from which you take language to author your Features. Dan argues (and I see the same thing) that the more domains you add in the more concerns that are included, the more likely something is going to change and thus the more brittle your Features. I discuss the same in more pedestrian terms, in this article; see North for the more rigorous treatment (and for other knowledge-rich nuggets).
The Business Analyst is a Role
A quick aside before we dive in, today. While I keep referring to "The Business Analyst", I'm not saying that there must be a separate person on the team who's title starts with a "B" and ends with a "t". I'm saying that there's a mindset/perspective embodied in a role known as "the Business Analyst." So, when I say, "The Business Analyst" I simply mean to say, "whoever is doing this work, with the BA mindset active."
Principles for Writing Cucumber Features
Write Features as if you were the Business Analyst
One common mistake when getting started with Cucumber is to include steps that are expressed in terms of underlying technical details. In fact, the Cucumber adaptor for Rails (via the cucumber-rails gem.) includes a number of step definitions (within web_steps.rb) that specifically call for xpath or CSS selectors. This is a bit unfortunate because to realize the total value of your Features, they need to be expressed in a way that survives changes in underlying implementation details.
Don't Be Misled By OOTB Steps
This is not to say the Business Analyst should be willfully ignorant of the implementations; quite the contrary. For example, cucumber-rails's web_steps.rb comes with a step definition that matches the pattern "Then I am on <page-name>". You might be tempted to include this in your Scenario to verify that clicking on a navigation element brought you to the correct page. However, the implementation of that step simply checks to verify that the URI of the current page matches that of the targeted page. But, if you have forgotten to define a route for that page, the URI will still match, but Rails will render the "Route Error" page. It's more correct to check for, say, the title of the page or some element that would only show up if the correct page was rendered.
The balance, lies in the perspective of the Business Analyst. Remember, this is the role that must understand both sides of the equation: the requirements as they are motivated by business concerns and the implementation details so far that they influence what's feasible to do with this system. It's from this position that one can write Features that are likely to last: informed by technical details and articulated in terms of elements of the User Interface.
Write Features in terms of the visible User Interface
A related principle is to articulate the Feature steps in terms of elements of the User Interface (UI). Terms like "buttons", "pull-downs", "title", "navigation bar", etc. are about as technical as one should get without risking losing the Product Owner who's expertise is in the business, not software development.
In practice it is helpful to not just agree on what the individual widgets are called, but to also develop an agreed-upon vocabulary for common parts of the page. Common parts include:
- Header and Footer
- Navigation Bar
- Status Message Area
- Main Body
There will also be elements that are repeated across your application. For example, if there is a heavy social networking component to your webapp, perhaps the set of "follow" buttons (e.g. reporting to your onlines friends that you've just bought the hip new new Thing... we'd present a series of buttons for Facebook like/share, Twitter, etc.)... it will facilitate language if you coin a term for that set of social networking controls: "Like Button Bar"? "Social Clicks"? Whatever you choose, it's the job of the Business Analyst to ensure that a shared vocabulary develops.
By sticking to the UI, your Features will be both concrete (more easily implementable) and better understood by both parties (i.e. Product Owner and Engineering). By developing a meaning-rich vocabulary (and implementing Features in these terms is what facilitates this shared semantic), you can bring the two sides of the team closer together. It means that misunderstandings can bubble-up faster (remember, the sooner you discover a defect, the cheaper it is to fix it, generally).
For the users of the program, the UI is the software. Keep Feature Steps in terms of the UI.
Stay DRY
DRY is an acronym for "Do not Repeat Yourself" (see
Wikipedia article for a deeper explanation) and it applies just as well to Feature Step writing as it does to software coding. The essence of this advice is to take care to minimize the amount of overlap between Features and their Scenarios. This is another example of where it pays significantly for the Business Analyst to have a working understanding of how the software is functioning. If you have already written a Feature+Scenario that exercises selecting an item from a list, no need to repeat verifying that behavior in another Feature+Scenario.
Features as Functional Tests
This become especially poignant as the project grows in size. One of the enemies of Continuous Integration (CI) is long running builds.
Long running CI builds create all kinds of problems: they lengthen the commit dance which slows down disciplined developers; they dampen the whole value of the Continuous nature of CI because the time window is larger and thus more developers' changes start to pile on. Builds that push past 15 minutes start to manifest these issues. So, in the interest of maintaining the value of Continuous Integration, the full build (which includes unit and functional tests) should run as fast as possible.
Quite often the longest running component of these full builds are the functional tests. Cucumber Features in the context of requirements analysis are User Stories; but Cucumber Features in the context of verification (i.e. executing the Scenarios) are, in fact, functional tests. To the extent that there is coverage overlap of Scenarios, we're duplicating computing effort (exercising the software in nearly the same way) with no added value. This waste needlessly extends the length of the overall build. In this way, Features written in an unskillful way, endanger the value of the CI-build -- a cornerstone of Agile software development.
The Business Analyst, as the author of Features and their Scenarios, is a key player in ensuring that the functional test portion of the overall build executes as quickly as possible without reducing the confidence in correctness that these tests bring.
Practices for the Writing Cucumber Features
With those two guidelines in mind:
- Write Features with the Business Analyst Mindset;
- Keep Features DRY.
Here are some concrete techniques that I have found to work in the field.
Create and maintain a lexicon of Cucumber Steps
Create a page in the project wiki (in the Requirements section) to maintain a dictionary of Cucumber Steps. Organize the page into sections including:
- a section for common steps;
- a section for each major feature set;
- a glossary of Domain and Visible Software Terms.
Within the Step definition sections, include a table with the following columns:
- Template -- the generic form of the Step, with clear typographic notation to indicate the "variables" in the Step.
- Meaning -- description of what the Step does. Include a clear definition for each "variable" and the expected set of values.
- Examples -- like all technical documentation, nothing makes it clearer than a reasonable example. Unless it is absolutely obvious how one would write a step, include at least one example.
In essence, this page codifies of the shared vocabulary of the project's requirements. The Product Owner (through the Business Analyst) contributes Domain-specific terms and their bias to the solution. The Engineering team (again, through the Business Analyst) contributes names of widgets and other UI terms.
This page acts as a palette while writing new Feature+Scenarios. The goal should be to identify reusable steps (and often refactor an exist set of steps into a more generic one, especially in the early days of the project) and write new Feature Step using the existing vocabulary as much as possible. Don't torture the language, just look for reuse. At the same time, new Features bring new UI interactions and it is through writing Features that new kinds of Steps are discovered. As they are, add them to the page.
When we look at this documentation from an Engineering perspective, as we delve into how to implement Cucumber Feature Steps), we will see how technical concerns have an equal influence over the shape of this lexicon. In the end, however, this document sits squarely in the Business Analyst's area of concern.
Marry an Issue Tracking Ticket with a Cucumber Feature to Form Each User Story
A User Story, in its best incarnation, is a token to remind the team of an understanding around a specific requirement. In practice, there are two parts to a User Story, then:
- the lastest set of agreements, written down to the extent that the team need to so as to not forget.
- the workflow of the User Story, from conception to sign-off, tracked to help keep the whole team on the same page as to the "status" of this feature.
One way to handle these two aspects of the User Story is to create a Ticket in a flexible issue tracking system (I have personally used JIRA in the past and
loved it...I'll share more about how Atlassian's JIRA+Confluence combo is a killer solution to most software development efforts) and to link that Ticket to the
.feature
file checked into the VCS.
The role of the JIRA ticket is to track the workflow and discussion amongst the team regarding the user story. The .feature
is the home for the rest of the User Story: the narrative and agreed-upon details.
"Linking", here is simply including the URL to each artifact in the other:
- in the JIRA ticket, include the URL to the
.feature
file in your VCS via its web interface (both SVN and git provide these, OOTB, others may as well);
- in the
.feature
file, include the URL to the JIRA ticket.
Start with Two Scenarios: Main Flow and One Exception Flow
The practical starting point for keeping Features DRY is to start with the minimal set of Scenarios for each feature. Begin with just two Scenarios: one that covers the Main Flow or "Happy Path" and one that covers what happens when there's an "exceptional case" (usually responding to invalid user input).
The key idea is to include an additional scenario only when an additional UI treatment is introduced. In the Happy Path, there is often a message that indicates "success" to the user (e.g. "Your journal entry has been recorded."). However, if the user input fails form validation, for example, then the elements that make clear to the user how to fix the input now come into play (including highlighting around text fields and the presence of the error message in the status area.
Once those mechanisms are exercised, the value of testing for all the other conditions that cause these UI mechanisms to activate is significantly reduced. Such tests are better suited as verifications against the underlying "model" code: unit tests (i.e. verifying that when the application attempts to use invalid input, the validation code catches it). Here we see, again, that the Business Analyst, the author of these functional tests, is well-served understanding how the underlying software is structured.
Next...
In this installment of our series, we've covered what life is like for the Business Analyst writing Cucumber Features. Hopefully, this description starts to illuminate the power of using Cucumber Features as the center-piece for BDD -- since they clearly sit right in the Business Analyst's purview, they are the confluence of business desire and software implementation concerns. Because Features are executed (and indeed, incorporated in the CI build), the Business Analyst looks to keep the formal Scenarios tight and DRY.
With the bryne starting to work its way in, we're ready to turn our attention to the full pickling process: how the raw requirements meet and become infused with the salty world that is software engineering. We shift our focus from the Business Analyst to the Engineering team who is writing the Ruby code to implement the Cucumber Steps...