Cucumber

cucumber

Cucumber is a very good tool that supports Behaviour Driven Development (BDD).
I have been working with Cucumber a lot over the last couple of years and have also made quite a few mistakes.

In this blog I will describe a way of working with Cucumber and Gherkin I think works best.
A kind of Best Practice if you will. I am very much aware there are different ways of working
with Cucumber and using Gherkin. I also think that the official documentation contradicts itself, making
different interpretations very possible…

It has been a learning curve I must admit, and I have seen it done beautifully and very ugly. I
have also been part of the ugly versions 😄…

Cucumber / Gherkin

After working with cucumber, lots of discussions with many colleagues and reading about it on the Internet, I think I have found a way of working with Cucumber that works for me and conforms with at least some of the
main schools of thought.

Here it goes…

Feature file(s)

The structure of a Scenario in a feature file should be like

Given (0..n)
(And/But)
(And/But)
When (1)
Then (1..n)
(And/But)
(And/But)

Given:

  • 0 or more (N) steps
  • 0 if no special preparation required (which is rare).
  • N steps if more settings need to be prepared before the “user” arrives at the specific test situation
  • It contains only setup steps leading up to the actual test. Examples:
    • open the browser
    • setting up test data
    • setting the browser format
    • navigate to specific page
    • Filling in fields as preparation to the test moment

When:

  • 1 stap (there can be only one)
  • The one and only action that leads to the asserts that follow.
  • Contains only the user action. Examples:
    • button click
    • filling in a field/form if that leads to validation action
    • Time travel

Then:

  • 1 or more (N) steps;
  • without Then there is no test (a test needs asserts)
  • Contains only expects and asserts

In general

  • Do not use technical language anywhere in the feature-file. Use only functional / user language. e.g. do not use terms like modal / service / true / camelCasingStuff / etc.
  • Talk in specified form. e.g. first person singular or third person but be consequent and consistent. Example:
    • When I send my credentials
  • Write in readable language (like a story)
  • Avoid code in your steps if at all possible (who is going to test the test?). Rather, add more Givens (And/But) than if statements in your steps.
    • If you are writing more (plumbing) code to keep the tests working than you have actual code you are doing it wrong!
  • Try to keep the number of steps in the scenario limited.
  • Avoid using the Background too much. It does not promote readability, and a When step should never be put into the Background.
  • A step must only do what it describes with no side effects!
  • Do not name UI elements by name. Not When I press the submit button but When I send my credentials

Step versus Feature files

Step-files

There are 3 different steps in step files:

  • Initiators
  • Mutators
  • Validators

For a flow you need one (1) Initiator followed by possible Mutators and required Validators

In the steps file you can recognise:

  • Initiators as Given
  • Mutators as When
  • Validators as Then

Feature-files

A test is build up according to an Arrange, Act en Assert schema in the feature-file.
The Arrange stage can contain an Initiator and multiple Mutators.
The Act stage always contains one Mutator.
The Assert stage contains only Validators
Here it also important to differentiate between the different stages.

In the feature file you can recognise:

  • the Arrange stage as Given line followed by And and/or But lines
  • the Act stage as a single When
  • the Assert stage as Then lines followed by And and/or But lines

Comparison

It is actually kinda sad that the step-file, and the feature-file use the same names (Given/When/Then) for different things.
It does therefore not mean that they need to be synchronised!

Discussion

In the official documentation you can find the following description (parts):

Given

[…]
The purpose of Given steps is to put the system in a known state before the user (or external system) starts interacting with the system (in the When steps). Avoid talking about user interaction in Given’s. If you were creating use cases, Given’s would be your preconditions.
[/…]

But the following about…

When

[…]
It’s strongly recommended you only have a single When step per Scenario. If you feel compelled to add more, it’s usually a sign that you should split the scenario up into multiple scenarios.
[/…]

After lots of thought and discussion I concluded this to mean that, e.g. filling a form, not always has to be seen as user interaction in every scenario.
You can interpret (and I do) this to be following in mock data before the actual test (When).
If you explain it like this everything gets its place quite handily, but I am very much aware that this is playing with words and that an equally good explanation can be that a when is needed for every “action”. but that would violate the “avoid using more that one when” admonition.

Good luck finding your own way :-)

Conclusion

My description above is not “The one true way” but experience enhances my conviction that it is a good way of working. Take the time to explore your options with your team and company.
The time spent in the beginning is worth it.
Write down the reasons for certain choices and review them. Be especially careful with allowing technical language in your feature files. You won’t recover easily from that mistake :-)

If you do not agree of have enhancements please leave them in the comments below…