If you are going to use Specification by Example then start by specifying the business rules.
There are lots of ways to write scenarios within Gherkin – the language used to specify requirements in Cucumber – and I have a distinct preference for certain style. I advocate testing against business rules. This increases the robustness of the tests because they aren’t tied to a particular user interface (UI). It also means the tests run faster. And finally it lowers the cost of automated testing.
To ensure I get what I want I gave my current team four guidelines for writing their Gherkin scenarios:
- Define the business logic
- Use business language
- Pretend there is no user interface
- Focus on state
Define the business logic
Generally the product owner and business analysts know the business rules but the developers do not. So I want tests that make the business rules explicit. If the systems breaks the business rules then the tests should break. If the system meets the business rules then the tests should run green.
Scenarios articulating business rules have the benefit that the product owner, and other people from the business, are more likely to understand them.
Concentrating on the business logic also means you can test under the UI (e.g. via an API or service layer). The tests will run faster and be independent of specific UI elements (buttons and screens). The tests will apply even if there are multiple simultaneous UIs to the same thing e.g. add data via a web UI and add the same data via a mobile specific UI.
Use business language
A key part of Specification by Example is to achieve “Ubiquitous Language”, i.e. the business, tests and code all using the same terms. This aids communication between the various people on the team and between the team and the rest of the organisation.
Pretend there is no user interface
Everybody I’ve met that is new to Gherkin starts with an Imperative style of scenarios. This type of scenario fills in fields and clicks through screens. The Imperative approach is simple and intuitive and reflects what manual testers do.
But I hate the Imperative style with a passion. I find tests based on the specific UI to be brittle, expensive and slow. Not characteristics that are desirable in an automated test.
Here’s a real Gherkin scenario somebody on a previous team produced. The business domain is News production. Aside from the fact the Gherkin syntax is syntactically dodgy the scenario is terribly Imperative. There are a lot of specific references to the UI, e.g. pages, the “Save” button and the need to “click” it. None of which is about how the business operates. None of which particularly helps as UIs have a tendency to change. And although the business rule is in there, it is tied to that page and no other. Nothing is said about any other page where it might be possible to create a Diary Entry.
Health Warning: Do Not Try This At Home – Example Included Just To Illustrate What Not To Do
# Horrible imperative scenario showing bad practice Scenario: Minimum New Diary Entry Given I am looking at a "New Diary Entry" page in the "West" diary When I fill the following fields: | Field | Information | | Slug | Syria | | Summary | Syria air strikes target civilians | And I click on "Save" button Then I see the "West Diary" page And I see a table of "DiaryEntries" in the "other" section with: | Slug / Angle | Location | Summary | People and resources | Content | | Syria | | Syria air strikes target civilians | | |
To encourage a Declarative style of Gherkin I tell my team to pretend there is no user interface.
Focus on state
From my simplistic perspective business rules are constraints on how the state of the business is allowed to change. So I advocate Gherkin scenarios that focus on state. A simple template for that kind of scenario is:
# Template for state based business rule Scenario: business rule in words Given the current state relevant to the business rule When I try to change part of the state Then the state is different or the system complains about an error
Some people find the concept of state a bit tricky, so here is a template assuming a database is the repository. This is still the same state based logic, but just emphasising that the state of interest is the contents of the database.
# Template for business with database Scenario: business rule in words Given existing data in the database When I try to add/update/delete some data Then the data in the database is different or the system complains about an error
Now for the Declarative alternative to the Imperative scenario I gave above. The happy path is about creating a entry with only the mandatory fields; everything else is optional.
Scenario: Slug and Summary are mandatory and everything else optional Given the "West" Diary is empty When I add a Diary Entry to the "West" Diary with a Slug of "Syria" and Summary of "Syria air strikes target civilians" Then the "West" Diary has a Diary Entry with a Slug of "Syria" and Summary of "Syria air strikes target civilians"
The happy scenario should be complemented with unhappy scenarios. For example ensuring there is a Slug.
Scenario: A Diary Entry must have a Slug Given the "West" Diary is empty When I add a Diary Entry with no Slug Then the "West" Diary is still empty And a "Slug is mandatory" error occurs
Notice that these scenarios apply to the entire system. So if there are alternative UIs (web + mobile) the same business rule applies to both. It doesn’t matter where in the system a Diary Entry is being added, it must always have a Slug.
This post is part of a series on Specification by Example.
The point that worries me in this approach (I have considered taking it as well) is that reuse of the steps can be very limited, because a lot of code is put into the actual implementation of a step. For example take the first Given: being empty may have a certain meaning in the context of the scenario, probably not having any entries. In the context of another scenario empty could very well mean that there are no reviewers or writers. That means that this become a way to write user story alike scripts, which is of great value, especially when you can automatically test them, but. Ahm. I don’t know.