Working Together

Cucumber features are what Gojko Adzic[23] calls living documentation. That term neatly sums up the two main benefits of using Cucumber:

  • Living: It tests the system automatically so you can work on it safely.

  • Documentation: It facilitates good communication about the current or planned behavior of the system.

When your team is struggling with Cucumber, the problems you’re having will hit you in one of these two places. Either they’ll result in Cucumber scenarios that provide poor feedback for the developers or they’ll mean Cucumber fails to help your team communicate. We’ll start by looking at what might be holding you back from making the features work as a communication tool.

Incidental Details

Consider the following scenario for an online email client:

 
Scenario:​ Check inbox​
 
Given ​a User ​"Dave"​ with password ​"password"​​
 
And ​a User ​"Sue"​ with password ​"secret"​​
 
And ​an email to ​"Dave"​ from ​"Sue"​​
 
When ​I sign in as ​"Dave"​ with password ​"password"​​
 
Then ​I should see 1 email from ​"Sue"​ in my inbox

There is a lot of detail in this scenario: we have the username and password of the main actor, Dave, and we also have the username and password of another user, Sue. The usernames are quite useful, because they help tell the story of the scenario, but the passwords are just noise: the passwords of the users have nothing to do with what’s being tested and in fact are making it harder to read. For example, Sue has a different password than Dave. As you read the scenario, wondering whether this is relevant, you’re distracted from the main point of the scenario: to check that Dave can see Sue’s email.

We call details like the passwords incidental details,[24] which are details that are mentioned in the scenario but that actually have no relevance to the purpose of the scenario. This kind of irrelevant detail makes the scenario harder to read, which in turn can cause your stakeholders to lose interest in reading them. Let’s rewrite the scenario without the passwords:

 
Scenario:​ Check inbox​
 
Given ​a User ​"Dave"​​
 
And ​a User ​"Sue"​​
 
And ​an email to ​"Dave"​ from ​"Sue"​​
 
When ​I sign in as ​"Dave"​​
 
Then ​I should see 1 email from ​"Sue"​ in my inbox

This is definitely an improvement, making it easier to read and understand the essence of the scenario. Let’s try stripping away some more of the noise:

 
Scenario:​ Check inbox​
 
Given ​I have received an email from ​"Sue"​​
 
When ​I sign in​
 
Then ​I should see 1 email from ​"Sue"​ in my inbox

Now we have a simple three-step scenario that’s clear and concise. It’s also more maintainable: if our product owner wants us to change the authentication mechanism, we can just rewrite the underlying step definition code without having to touch the features.

Avoiding Incidental Details

If you’re a programmer, you’re probably practiced at filtering out irrelevant details as you read code each day. Bear that in mind when you write scenarios, because you may not even notice these incidental details slipping in.

Try to avoid being guided by existing step definitions when you write your scenarios and just write down exactly what you want to happen, in plain English. In fact, try to avoid programmers or testers writing scenarios on their own. Instead, get nontechnical stakeholders or analysts to write the first draft of each scenario from a purely business-focused perspective or ideally in a pair with a programmer to help them share their mental model. With a well-engineered support layer, you can confidently and quickly write new step definitions to match the way the scenario has been expressed.

Imperative Steps

In computer programming, there are two contrasting styles for expressing the instructions you give to a computer to make it do something for you. These styles are called imperative programming and declarative programming.

Imperative programming means using a sequence of commands for the computer to perform in a particular order. Ruby is an example of an imperative language: you write a program as a series of statements that Ruby runs one at a time, in order. A declarative program tells the computer what it should do without prescribing precisely how to do it. CSS is an example of a declarative language: you tell the computer what you want the various elements on a web page to look like, and you leave it to take care of the rest.

Gherkin is, of course, an imperative language. Cucumber executes each step in a scenario, one at a time, in the sequence you’ve written them in. However, that doesn’t mean those steps need to be read like the instructions for assembling a piece of flat-pack furniture. Let’s take a look at a typical example written in an imperative style:

 
Scenario:​ Redirect user to originally requested page after logging in​
 
Given ​a User ​"dave"​ exists with password ​"secret"​​
 
And ​I am not logged in​
 
When ​I navigate to the home page​
 
Then ​I am redirected to the login form​
 
When ​I fill in ​"Username"​ with ​"dave"​​
 
And ​I fill in ​"Password"​ with ​"secret"​​
 
And ​I press ​"Login"​​
 
Then ​I should be on the home page

What’s good about this scenario? Well, it uses very generic step definitions, like /^I fill in "(.*)" with "(.*)"$/", which means you can write lots of scenarios like this without having to create much step definition code. You could also probably just about make the argument that it acts as a guide to what the user interface will look like, since it names the fields and buttons that will be used in the login form.

However, when a team uses such an imperative style for their step definitions, it won’t be long before they’re experiencing the pain of brittle tests and bored stakeholders. Scenarios written in this style are not only noisy, long, and boring to read, but they’re easy to break: if the user-experience people decided to change the wording on the submit button from Login to Log in, the scenario will fail, for no good reason at all.

Worst of all, scenarios that use generic step definitions like this are failing to create their own domain language. The language of this scenario, using words and phrases like fill in and press, is expressed in the domain of user interface widgets, a generic and relatively low-level domain.

Use a Declarative Style Instead

Let’s raise the level of abstraction in this scenario and rewrite it using a more declarative style:

 
Scenario:​ Redirect user to originally requested page after logging in​
 
Given ​I am an unauthenticated User​
 
When ​I attempt to view some restricted content​
 
Then ​I am shown a login form​
 
When ​I authenticate with valid credentials​
 
Then ​I should be shown the restricted content

The beauty of this style is that it is not coupled to any specific implementation of the user interface. This same scenario could apply to a thick-client or mobile application. The words it uses aren’t technical and are instead written in a language (unauthenticated, restricted, credentials) that any stakeholder interested in security should be able to clearly understand. It’s by expressing every scenario at this level of abstraction that you discover your team’s ubiquitous language.

It’s true that using declarative style will mean you have to write more step definitions, but you can keep the code in those step definitions short and easy to maintain by pushing the actual work off into helper methods in your support code. We’ll show you how to do this in Chapter 8, Support Code.

Duplication

All good computer programmers understand how destructive duplication is to the maintainability of their code. Yet we often see duplication rife in teams’ Cucumber features. Duplication obviously makes your scenarios brittle, but it also makes them boring.

Gherkin has the Background and Scenario Outline keywords you can use to reduce duplication, as we showed you in Chapter 5, Expressive Scenarios, but stay vigilant for where the duplication is a sign that your steps are written at too low a level of abstraction. If you have steps that are too imperative, any amount of moving them into Backgrounds or Scenario Outlines won’t help you. Work with nontechnical members of your team to get their feedback about the kind of duplication they can accept and the kinds that make their eyes glaze over.

Let Your Examples Flow
by Dan North
Dan North

The DRY principle[25] (Don’t Repeat Yourself) says that the definition of any concept should appear once and only once in your code. This is an admirable aim in that if you have to change the behavior of the system, you want to be able to change it in one place and be confident that your change will apply consistently across the codebase. If there are multiple definitions of that behavior scattered around the code, the chances are that not only will you not catch them all but someone before you didn’t catch them all and the multiple definitions are already inconsistent, and who wants that?

However, when you are using examples to drive your code, there is another principle in play that I believe trumps the DRY principle: the examples should tell a good story. They are the documentation narrative that will guide future programmers (including you when you come back to change this code in three months time and you’ve forgotten what it does). In this case, clarity of intent is found in the quality of the narrative, not necessarily in minimizing duplication.

Some years ago I had my first experience of pair programming with Martin Fowler. That is, I had done quite a bit of pair programming, just not with Martin before. We were looking at some Ruby code I had written test-first, and Martin asked to see the tests "to find out what the code does." Then he did a rather odd thing. He started moving the tests around. I had a few helper classes and utility methods in the source file, neatly at the end out of the way. He moved them up and dropped them inline just ahead of the first test that used them.

Madness! I thought—now the supporting code is all over the place! It really offended my sense of tidiness. But then I saw a pattern beginning to emerge: the test code was starting to read like a story. He would introduce these little methods and classes just before their one walk-on line in the narrative. It was quite an eye-opener for me. The test code flowed and unfolded the story of the class under test.

The a-ha! moment for me was when I imagined reading a book where the plot and characters had been DRYed out. Everything would be in footnotes or appendixes. All the character descriptions, plot elements, subtexts, and so on, would be carefully extracted into fully cross-referenced paragraphs. That is great if you are reading an encyclopedia but not so appropriate if you want to get into the flow and find out what happens. You would be forever flicking back and forth in the book, and you would very quickly forget where you even were in the story. In the words of the old joke, dictionaries have lousy plots, but at least they explain all the words as they go.

Some people refer to this as the DAMP principle: Descriptive and Meaningful Phrases. When you’re writing examples, readability is paramount, and DAMP trumps DRY.

Ubiquitous What?

The ubiquitous language your team uses will be driven by the domain you’re working in. If you’re building a system for live-music fans, your ubiquitous language will include words like concert, performance, artist, and venue. If you’re building a catalog of TV shows, you’ll have words like broadcaster, genre, duration, and transmission date in your ubiquitous language.

The point is for everyone on the team to use the same words, everywhere. It’s not OK to have a database table called tbl_Performer if the rows in that table represent things that most of the team refers to as artists. Wherever you see schism like this, stop, decide which is the right word to use, make the appropriate correction, and then stick with it.

We talk about developing a ubiquitous language because it’s an ongoing process. That development takes work. It takes effort to really listen to one another and agree on the words you’ll use, and it takes discipline to stick to those commitments.

The rewards are great. Teams that use a ubiquitous language make fewer mistakes and enjoy their work more because they can communicate effectively about the work. When a team doesn’t appreciate the value of a ubiquitous language, they’ll be careless with the wording of their scenarios, missing a valuable opportunity to build strong bridges between the technical and business-focused sides of the team. When you try to correct people or clarify terminology, you might end up feeling like you’re just being picky.

Take time to explain the concept of a ubiquitous language to your team and what its benefits are. Once everyone understands why it’s important, you’ll find they’re much more willing to help make the effort to discuss and decide on the right words to use.

Used correctly, Cucumber helps a team to develop their ubiquitous language. When programmers and businesspeople work together to write scenarios, you’ll find all kinds of arguments breaking out about how precisely to word things. Great! Each of those disagreements has exposed a potential misunderstanding between the two groups, in other words, a bug magnet. For a new team, these sessions can be hard at first, but as the language develops, they get easier and easier. Three Amigos is a good way to structure these meetings.

Siloed Features

Cucumber can feel like a very technical tool. It’s run from the command line, and the feature files are designed to be checked into source control along with the code that they test. Yet it’s supposed to help the business stakeholders on your team feel more in control of the development process. When testers and developers tuck their features away in source control, the rest of the team can feel as though their documentation had been locked away in a cupboard to which they don’t have the keys.

Your features act as a design tool for specifying new features, but they also act as a great reference document for what the system already does today. For a system of any significant size, no one person will remember exactly what it will do in every situation, so when you get a bug report from a user or are considering adding new functionality to some part of the system, you want this reference right at your side.

Cucumber itself has only limited support for sharing features in a way that’s accessible for nontechnical audiences, but there are plenty of plug-ins and tools springing up around it that do. For example, if you use GitHub for source control, the pages for your project will have syntax-highlighted features that people can even comment on.

Relish[26] is a service that was created by members of the Cucumber and RSpec teams to provide an easy way to publish Cucumber features as documentation. The RSpec project now uses its Relish documentation as its home page, and your team can use it too.

You can achieve at least half of the benefit of Cucumber just by having the discipline to sit down with your business stakeholders and write scenarios collaboratively. The conversations sparked by that process will uncover so many potential bugs or schedule overruns that you’ll already have made a huge win, even if you choose to never automate your features.

Assuming you do want to automate them, however, read on to find out how to do it well.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.231.194