BDD 101: Writing Good Gherkin

So, you and your team have decided to make test automation a priority. You plan to use behavior-driven development to shift left with testing. You read my “BDD 101 Series” up through the previous post. You even peeked at Cucumber or another BDD framework on your own.  That’s great!  Big steps!  And now, you are ready to write your first Gherkin feature file.  You fire open Notepad++ with a Gherkin UDL, you type “Given” on the first line, and…

Writer’s block.  How am I supposed to write my Gherkin steps?

Good Gherkin feature files are not easy to write at first. Writing is definitely an art. With some basic pointers, and a bit of practice, Gherkin becomes easier. This post will cover how to write top-notch feature files.

Proper Behavior

The biggest mistake BDD beginners make is writing Gherkin without a behavior-driven mindset. They often write feature files as if they are writing “traditional” procedure-driven functional tests: step-by-step instructions with actions and expected results. HP ALM, qTest, and many other test repository tools store tests in this format. These procedure-driven tests are often imperative and trace a path through the system that covers multiple behaviors. As a result, they may be unnecessarily long, which can delay failure investigation, increase maintenance costs, and create confusion.

For example, let’s consider a test that searches for images of pandas on Google. Below would be a reasonable test procedure:

  1. Open a web browser.
    1. Web browser opens successfully.
  2. Navigate to https://www.google.com/.
    1. The web page loads successfully and the Google image is visible.
  3. Enter “panda” in the search bar.
    1. Links related to “panda” are shown on the results page.
  4. Click on the “Images” link at the top of the results page.
    1. Images related to “panda” are shown on the results page.

I’ve seen many newbies translate a test like this into Gherkin like the following:

# BAD EXAMPLE! Do not copy.
Feature: Google Searching

  Scenario: Google Image search shows pictures
    Given the user opens a web browser
    And the user navigates to "https://www.google.com/"
    When the user enters "panda" into the search bar
    Then links related to "panda" are shown on the results page
    When the user clicks on the "Images" link at the top of the results page
    Then images related to "panda" are shown on the results page

This scenario is terribly wrong. All that happened was that the author put BDD buzzwords in front of each step of the traditional test. This is not behavior-driven, it is still procedure-driven.

The first two steps are purely setup: they just go to Google, and they are strongly imperative. Since they don’t focus on the desired behavior, they can be reduced to one declarative step: “Given a web browser is at the Google home page.” This new step is friendlier to read.

After the Given step, there are two When-Then pairs. This is syntactically incorrect: Given-When-Then steps must appear in order and cannot repeat. A Given may not follow a When or Then, and a When may not follow a Then. The reason is simple: any single When-Then pair denotes an individual behavior. This makes it easy to see how, in the test above, there are actually two behaviors covered: (1) searching from the search bar, and (2) performing an image search. In Gherkin, one scenario covers one behavior. Thus, there should be two scenarios instead of one. Any time you want to write more than one When-Then pair, write separate scenarios instead. (Note: Some BDD frameworks may allow disordered steps, but it would nevertheless be anti-behavioral.)

This splitting technique also reveals unnecessary behavior coverage. For instance, the first behavior to search from the search bar may be covered in another feature file. I once saw a scenario with about 30 When-Then pairs, and many were duplicate behaviors.

Do not be tempted to arbitrarily reassign step types to make scenarios follow strict Given-When-Then ordering. Respect the integrity of the step types: Givens set up initial state, Whens perform an action, and Thens verify outcomes. In the example above, the first Then step could have been turned into a When step, but that would be incorrect because it makes an assertion. Step types are meant to be guide rails for writing good behavior scenarios.

The correct feature file would look something like this:

Feature: Google Searching

  Scenario: Search from the search bar
    Given a web browser is at the Google home page
    When the user enters "panda" into the search bar
    Then links related to "panda" are shown on the results page

  Scenario: Image search
    Given search results for "panda" are shown
    When the user clicks on the "Images" link at the top of the results page
    Then images related to "panda" are shown on the results page

The second behavior arguably needs the first behavior to run first because the second needs to start at the search result page. However, since that is merely setup for the behavior of image searching and is not part of it, the Given step in the second scenario can basically declare (declaratively) that the “panda” search must already be done. Of course, this means that the “panda” search would be run redundantly at test time, but the separation of scenarios guarantees behavior-level independence.

Remember, behavior scenarios are more than tests – they also represent requirements and acceptance criteria. Good Gherkin comes from good behavior.

Phrasing Steps

How you write a step matters. If you write a step poorly, it cannot easily be reused. Thankfully, some basic rules maintain consistent phrasing and maximum reusability.

Write all steps in third-person point of view. If first-person and third-person steps mix, scenarios become confusing. I even dedicated a whole blog post entirely to this point: Should Gherkin Steps Use First-Person or Third-Person? TL;DR: just use third-person at all times.

Write steps as a subject-predicate action phrase. It may tempting to leave parts of speech out of a step line for brevity, especially when using Ands and Buts, but partial phrases make steps ambiguous and more likely to be reused improperly. For example, consider the following example:

# BAD EXAMPLE! Do not copy.
Feature: Google Searching

  Scenario: Google search result page elements
    Given the user navigates to the Google home page
    When the user entered "panda" at the search bar
    Then the results page shows links related to "panda"
    And image links for "panda"
    And video links for "panda"

The final two And steps lack the subject-predicate phrase format. Are the links meant to be subjects, meaning that they perform some action? Or, are they meant to be direct objects, meaning that they receive some action? Are they meant to be on the results page or not? What if someone else wrote a scenario for a different page that also had image and video links – could they reuse these steps? Writing steps without a clear subject and predicate is not only poor English but poor communication.

Also, use appropriate tense for each type of step. Givens should always use present perfect tense, and Whens and Thens should always use present tense. Rather than take a time warp back to middle school English class, let’s illustrate tense with a bad example:

# BAD EXAMPLE! Do not copy.
Feature: Google Searching

  Scenario: Simple Google search
    Given the user navigates to the Google home page
    When the user entered "panda" at the search bar
    Then links related to "panda" will be shown on the results page

The Given step above indicates an action when it says, “The user navigates.” Actions imply the exercise of behavior. However, Given steps are meant to establish an initial state, not exercise a behavior. This may seem like a trivial nuance, but it can confuse feature file authors who may not be able to tell if a step is a Given or When. Using present perfect tense indicates a state rather than an action.

The When step above uses past tense when it says, “The user entered.” This indicates that an action has already happened. However, When steps should indicate that an action is presently happening. Plus, past tense here conflicts with the tenses used in the other steps.

The Then step above uses future tense when it says, “The results will be shown.” Future tense seems practical for Then steps because it indicates what the result should be after the current action is taken. However, future tense reinforces a procedure-driven approach because it treats the scenario as a time sequence. A behavior, on the other hand, is a present-tense aspect of the product or feature. Thus, it is better to write Then steps in the present tense.

The corrected example looks like this:

Feature: Google Searching

  Scenario: Simple Google search
    Given a web browser is at the Google home page
    When the user enters "panda" into the search bar
    Then links related to "panda" are shown on the results page

And note, all steps are written in third-person.

Choices, Choices

Another common misconception for beginners is thinking that Gherkin has an “Or” step for conditional or combinatorial logic. People may presume that Gherkin has “Or” because it has “And”, or perhaps programmers want to treat Gherkin like a structured language. However, Gherkin does not have an “Or” step. When automated, every step is executed sequentially.

Below is a bad example based on a classic Super Mario video game, showing how people might want to use “Or”:

# BAD EXAMPLE! Do not copy.
Feature: SNES Mario Controls

  Scenario: Mario jumps
    Given a level is started
    When the player pushes the "A" button
    Or the player pushes the "B" button
    Then Mario jumps straight up

Clearly, the author’s intent is to say that Mario should jump when the player pushes either of two buttons. The author wants to cover multiple variations of the same behavior. In order to do this the right way, use Scenario Outline sections to cover multiple variations of the same behavior, as shown below:

Feature: SNES Mario Controls

  Scenario Outline: Mario jumps
    Given a level is started
    When the player pushes the "" button
    Then Mario jumps straight up
    
    Examples: Buttons
      | letter |
      | A      |
      | B      |

The Known Unknowns

Test data can be difficult to handle. Sometimes, it may be possible to seed data in the system and write tests to reference it, but other times, it may not. Google search is the prime example: the result list will change over time as both Google and the Internet change. To handle the known unknowns, write scenarios defensively so that changes in the underlying data do not cause test runs to fail. Furthermore, to be truly behavior-driven, think about data not as test data but as examples of behavior.

Consider the following example from the previous post:

Feature: Google Searching
  
  Scenario: Simple Google search
    Given a web browser is on the Google page
    When the search phrase "panda" is entered
    Then results for "panda" are shown
    And the following related results are shown
      | related       |
      | Panda Express |
      | giant panda   |
      | panda videos  |

This scenario uses a step table to explicitly name results that should appear for a search. The step with the table would be implemented to iterate over the table entries and verify each appeared in the result list. However, what if Panda Express were to go out of business and thus no longer be ranked as high in the results? (Let’s hope not.) The test run would then fail, not because the search feature is broken, but because a hard-coded variation became invalid. It would be better to write a step that more intelligently verified that each returned result somehow related to the search phrase, like this: “And links related to ‘panda’ are shown on the results page.” The step definition implementation could use regular expression parsing to verify the presence of “panda” in each result link.

Another nice feature of Gherkin is that step definitions can hide data in the automation when it doesn’t need to be exposed. Step definitions may also pass data to future steps in the automation. For example, consider another Google search scenario:

Feature: Google Searching

  Scenario: Search result linking
    Given search results for "panda" are shown
    When the user clicks the first result link
    Then the page for the chosen result link is displayed

Notice how the When step does not explicitly name the value of the result link – it simply says to click the first one. The value of the first link may change over time, but there will always be a first link. The Then step must know something about the chosen link in order to successfully verify the outcome, but it can simply reference it as “the chosen result link”. Behind the scenes, in the step definitions, the When step can store the value of the chosen link in a variable and pass the variable forward to the Then step.

Handling Test Data

Some types of test data should be handled directly within the Gherkin, but other types should not. Remember that BDD is specification by example – scenarios should be descriptive of the behaviors they cover, and any data written into the Gherkin should support that descriptive nature. Read Handling Test Data in BDD for comprehensive information on handling test data.

Less is More

Scenarios should be short and sweet. I typically recommend that scenarios should have a single-digit step count (<10). Long scenarios are hard to understand, and they are often indicative of poor practices. One such problem is writing imperative steps instead of declarative steps. I have touched on this topic before, but I want to thoroughly explain it here.

Imperative steps state the mechanics of how an action should happen. They are very procedure-driven. For example, consider the following When steps for entering a Google search:

  1. When the user scrolls the mouse to the search bar
  2. And the user clicks the search bar
  3. And the user types the letter “p”
  4. And the user types the letter “a”
  5. And the user types the letter “n”
  6. And the user types the letter “d”
  7. And the user types the letter “a”
  8. And the user types the ENTER key

Now, the granularity of actions may seem like overkill, but it illustrates the point that imperative steps focus very much on how actions are taken. Thus, they often need many steps to fully accomplish the intended behavior. Furthermore, the intended behavior is not always as self-documented as with declarative steps.

Declarative steps state what action should happen without providing all of the information for how it will happen. They are behavior-driven because they express action at a higher level. All of the imperative steps in the example above could be written in one line: “When the user enters ‘panda’ at the search bar.” The scrolling and keystroking is implied, and it will ultimately be handled by the automation in the step definition. When trying to reduce step count, ask yourself if your steps can be written more declaratively.

Another reason for lengthy scenarios is scenario outline abuse. Scenario outlines make it all too easy to add unnecessary rows and columns to their Examples tables. Unnecessary rows waste test execution time. Extra columns indicate complexity. Both should be avoided. Below are questions to ask yourself when facing an oversized scenario outline:

  • Does each row represent an equivalence class of variations?
    • For example, searching for “elephant” in addition to “panda” does not add much test value.
  • Does every combination of inputs need to be covered?
    • N columns with M inputs each generates MN possible combinations.
    • Consider making each input appear only once, regardless of combination.
  • Do any columns represent separate behaviors?
    • This may be true if columns are never referenced together in the same step.
    • If so, consider splitting apart the scenario outline by column.
  • Does the feature file reader need to explicitly know all of the data?
    • Consider hiding some of the data in step definitions.
    • Some data may be derivable from other data.

These questions are meant to be sanity checks, not hard-and-fast rules. The main point is that scenario outlines should focus on one behavior and use only the necessary variations.

Style and Structure

While style often takes a backseat during code review, it is a factor that differentiates good feature files from great feature files. In a truly behavior-driven team, non-technical stakeholders will rely upon feature files just as much as the engineers. Good writing style improves communication, and good communication skills are more than just resume fluff.

Below are a number of tidbits for good style and structure:

  1. Limit one feature per feature file. This makes it easy to find features.
  2. Limit the number of scenarios per feature. Nobody wants a thousand-line feature file. A good measure is a dozen scenarios per feature.
  3. Limit the number of steps per scenario to less than ten.
  4. Limit the character length of each step. Common limits are 80-120 characters.
  5. Use proper spelling.
  6. Use proper grammar.
  7. Capitalize Gherkin keywords.
  8. Capitalize the first word in titles.
  9. Do not capitalize words in the step phrases unless they are proper nouns.
  10. Do not use punctuation (specifically periods and commas) at the end of step phrases.
  11. Use single spaces between words.
  12. Indent the content beneath every section header.
  13. Separate features and scenarios by two blank lines.
  14. Separate examples tables by 1 blank line.
  15. Do not separate steps within a scenario by blank lines.
  16. Space table delimiter pipes (“|”) evenly.
  17. Adopt a standard set of tag names. Avoid duplicates.
  18. Write all tag names in lowercase, and use hyphens (“-“) to separate words.
  19. Limit the length of tag names.

Without these rules, you might end up with something like this:

# BAD EXAMPLE! Do not copy.

 Feature: Google Searching
     @AUTOMATE @Automated @automation @Sprint32GoogleSearchFeature
 Scenario outline: GOOGLE STUFF
Given a Web Browser is on the Google page,
 when The seach phrase "" Enter,

 Then  "" shown.
and The relatedd   results include "".
Examples: animals
 | phrase | related |
| panda | Panda Express        |
| elephant    | elephant Man  |

Don’t do this. It looks horrible. Please, take pride in your profession. While the automation code may look hairy in parts, Gherkin files should look elegant.

Gherkinize Those Behaviors!

With these best practices, you can write Gherkin feature files like a pro. Don’t be afraid to try: nobody does things perfectly the first time. As a beginner, I broke many of the guidelines I put in this post, but I learned as I went. Don’t give up if you get stuck.

This is the last of three posts in the series focused exclusively on Gherkin. The next post will address how to adopt behavior-driven practices into the Agile software development process.

11 thoughts on “BDD 101: Writing Good Gherkin

  1. Dileepa

    Hi,

    Thanks for the lots of information.I have couple of questions to be asked.

    1.Some companies like to automate user scenarios/business cases since that would be really handy before go live. Rather testing collection of activities testing a user scenario may cover lots of things.Also if anything is broken that could be easily found in user scenarios. Such case your number of steps in the scenario will be higher. Can you explain how you can you follow good practices at this point.
    (In my experienced we had to automate some user scenarios as it was really critical due to code changes.They are like business scenarios)

    2.If you have set of preconditions to be run before execute your tests what will be the best way to automate them? Do you think better to write them with the test? or any other idea?

    Thank you,
    Dileepa Ranaweera
    Quality Assistant Analyst

    Like

    1. Hi Dileepa,

      Thanks for reading my blog and for commenting! You raise good questions.

      For your first question, when you say “user scenario,” I presume you mean, “a scenario covering multiple behaviors to test more intense user interaction”? Think of these types of scenarios as no different from “regular” scenarios. Every behavior scenario should still cover one main behavior. However, for these “user” scenarios, the intended behavior is not the individual actions (“behaviors”) themselves but rather the interaction of these actions in concert. You should still have separate scenarios to cover each individual behavior. With this mindset, when you write “user” scenarios, your steps should be more general and even more declarative than normal. “User” scenarios should not necessarily have higher step count. As a general rule, scenarios should not be more than a dozen lines long.

      For example, consider testing an ATM. You may have a scenario for entering your debit card:
      Given the ATM is at the start screen
      When the user enters their debit card
      And the user enters their PIN correctly
      Then the ATM is at the home screen

      And a scenario for withdrawing cash:
      Given the user is at the ATM home screen
      When the user touches the “withdraw” button
      And the user enters “20” dollars
      Then the ATM dispenses “20” dollars
      And the user’s account is debited by “20” dollars

      You may have a “user” scenario like this:
      Given there are “100” users with valid debit cards
      When the users each withdraw between “20” and “100” dollars
      Then the ATM dispenses each withdraw correctly
      And each user’s account is debited correctly

      This is a trivial, spur-of-the-moment example, but it shows how “user” scenario steps can be less declarative. The part about entering the debit card is just assumed, and the mechanics of cash withdraw are stated as “what” and now “how”. The “how” can be handled in the underlying automation code by calling the other steps or helpers internally. Thus, the behavior in focus for the third scenario is the multi-user intensity, not the authentication or withdraw behaviors.

      For your second question, there are two primary ways to handle scenario preconditions. The first way is the Given step. The Given step is meant to set up initial state. A weak Given will check if a state is true and abort if not. A legitimate Given will put the system into the desired state. If scenarios within a feature file all have the same Givens, then they may be moved to a Background section. If there are a high number of Givens, then I recommend reducing them from being imperative to declarative. The second way to handle preconditions is with tagging and before hooks. For example, you could write a before scenario hook to construct a Selenium WebDriver instance for any scenario that has a “@selenium” tag. This strategy reduces a lot of redundant code, but it should be done only for preconditions/setup that are widely needed.

      I hope this helps!
      Andy

      Like

  2. Pingback: Winning Support for BDD – Automation Panda

  3. Pingback: Who Should Lead BDD? – Automation Panda

  4. Dinzy

    Hello,

    Thanks for sharing such important information with us.
    Looking at this post I can say that I am certainly not using my FitNesse in the best possible way. I have a doubt, though.

    In one of the tests, we have to fill a form with around 20 questions. It looks something like this:
    Given the user has permissions
    When the user answers the session
    Then the status for the session is displayed as Complete

    However, for the When clause, we have 20 steps, one for each question:
    |Click radiobutton|yes|
    |Fill fields|Field1|Field2|…
    |Select from dropdown|Item1|
    |Fill fields|Field3|Field4|…
    |Type|Comments1|
    ….
    ….
    ….

    This makes the Test Page very lengthy and difficult to read. Could you please provide me with a better approach for scenarios like this?

    Thanks,
    Dinzy

    Like

    1. Hi Dinzy,

      Thanks for reading my blog! I’m sorry it took me so long to reply to your question.

      Your question is very pertinent for BDD: What is the best way to capture test data? And your sensibilities are in the right direction. My advice is this: Write only the most pertinent test data in Gherkin, and put the rest into the automation layer. BDD is meant to be “Specification by Example”, and thus data inputs for behavior scenarios should represent examples of behavioral circumstances. Based on the scenario you provided, it looks like the main behavior in focus is completing the form and getting a success message. The specific input values, though they must be entered, are not of first importance when defining the desired behavior. These specific inputs would best be defined in the automation layer in the step definitions. Automation code can easily have methods/functions to handle the specific input operations. You may also want to consider putting the test data into some sort of text-based file (like a .csv, .json, .xml, .properties, etc.) that the automation framework can read in and use for this step.

      I hope this info helps!

      Andy

      Like

      1. Dinzy

        Thanks for the response, Andy. Adding the test data to a text-based file looks like a good solution to our problem. I will definitely try this approach.

        Like

  5. Pingback: ‑‑BDD; Automation without Collaboration – Automation Panda

  6. Dinzy

    Hello Andy,

    I have one more recurring question from my team.

    We have a scenario where:
    1) the user logs in and navigates to a certain menu,
    2) creates an instance (press add button on the page, a form is opened up, fill the form, press save button on the form),
    3) verifies that the newly created instance is displayed in the above page (only the name of the instance appears on the page as a link),
    4) click on this link,
    5) and verify that the fields have correct values. Ideally, this is one complete scenario.

    Given the user is logged in as administrator
    and the application is at the create page

    When the user creates an instance

    Then the instance is displayed at the page => This verification is important.

    (Given the instance is created and displayed) => not implemented currently

    When the user clicks on the new instance

    Then the fields are displayed with the correct values

    The first then is important to verify. Breaking the scenarios into several Given-When-Then scenarios would have several related scenarios, which would make them dependent to each other. In FitNesse, it would also increase the size of the tests.

    Also, the Given in the second case would be a repeated step. For the 2nd scenario, the Given assumes that the instance is created and displayed, which is basically the same as When and Then of the first scenario. We can still manage writing the GWT, but the step definition for 2nd Given would be the verification of the created instance, and hence, repeated code from 1st Then.
    Is it okay to have an empty Given in such case, i.e. a Given not doing anything or without any step definition?

    Thanks.

    Like

    1. Hi Dinzy,

      Sorry again for a slow response. Things have been busy!

      I think you could elegantly handle this example as one scenario like this:
      Given the user is logged in as administrator
      And the application is at the create page
      When the user creates an instance
      Then the instance is displayed at the page
      And the fields on the linked page are displayed with the correct values

      The final “And” step would click the link and do the required verification.

      You could split it into two scenarios. That would be advantageous if there are multiple ways to get to that link. Remember, BDD is about capturing DESIRED and INDIVIDUAL behaviors. Is the action of clicking the link and verifying its fields an individual behavior that could be reached in multiple ways and thus worthy of its own scenario, or is it totally dependent upon the instance creation?

      The empty Given, though, is not okay. Each scenario is independent, meaning the output of one does not become the input of another. The order scenarios appear in a feature file doesn’t matter. Think of it this way: Each scenario should start at login. If you were to write two scenarios, then the step definition for the second scenario’s Given must perform all of the same actions as the first scenario. That second Given could be “reduced” in that it includes login, navigation, and some initial interaction, but it still must be done. It’s best to write those basic initial actions as helper methods/classes so that they may be called by many different Given steps.

      Andy

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s