In previous post we had an overview of the Cucumber, Gherkin & feature file. Now let's see how to write test cases in feature files using Gherkin.
Anatomy of a feature-file
All non-blank lines in a feature file have to start with a valid Gherkin keyword. Some of them we discussed in the previous post. Here is the description of the main Gherkin keywords.
Feature:
The first Keyword in feature-file must be Feature, it must be followed by :
After Feature:
cucumber ignores all the text and lines for processing until a line starting with either Scenario
, Background,
or Scenario Outline
keyword is found. All the text in between is used only for reporting purposes.
The first line is used as the feature name, and the remaining lines (if present) are used as feature descriptions.
Scenario:
Scenario keyword must also be followed by :
.
Any text after :
in this line, is used for reporting purposes.
Steps:
“Steps” is not a Gherkin keyword but it's an integral concept.
Within a scenario, the keywords Given
, When
, Then
, But
and And
are used to mention steps. These keywords are not followed by any :
. Any text in the same line followed by these keywords is considered as a step.
The Cucumber engine looks for the step-definition files to understand what to do in these steps. Step-definition can be written in many programming languages as mentioned in the previous post. We will talk more about step-definition later here, first, let's look at the steps.
Let's take an example scenario of a web application where only the admin user should be able to view reports.
Scenario: Unauthorize admin reports access
Given website page "website-url" is open
And Have a "non ADMIN" user
When User logs in
Then User should be able to see user Home Page
But User should not see reports section
NOTE:
Cucumber is a BDD framework.Tests should only be about the behavior of the system. Tests should not expose internal details about the system.
In the above example, instead of “enter user id and password” I mentioned, “User logs in”. It's left to the step-definition file to decide how a user logs in. Those internal details shouldn’t be exposed to someone who is reading or writing the scenario, as those are irrelevant to the behavior under test.
Given
The step mentioned in Given
should be treated as a precondition for your test case. Do not start user interaction in Given
. This step should just set up your test system to an initial state, so it can start executing test-related steps.
When
When
is an action that is the essence of your test scenario?
Gherkin grammar doesn't stop you from having multiple When
, but for clarity purposes, you should use only one when
inside your scenario. Also, the steps in when
should perform the main action that you meant to test.
Then
This is where you validate your outcome of Given
and When
actions. Then
is like assertions in your Junit tests. But unlike Junit, this assertion should be on some observable outcome of the system under test.
It should not be validating some change in resources or a process within the system. As we discussed in our previous posts, BDD is about “what the system is doing”, leaving aside the technical know-how of how it’s doing.
But, And
Ideally Given
, When
, Then
are the only constructs a Scenario
should have. However, as per good design, each step should do only one thing, so for a real-life scenario, you might end up with multiple Given
and Then
statements. This is where you replace those successive Given
and Then
with And
and But
. like we did in the above example.
Below is a syntactically valid but BAD way to write the above scenario without And
and But
Scenario: Unauthorize admin reports access
Given website page "website-url" is open
Given Have a "non ADMIN" user
When User logs in
Then User should be able to see user Home Page
Then User should not see reports section
(*)
As we saw above, not all scenarios can be written with just Given
, When
, Then
steps. So we use And
and But
to express our scenario in a more linguistic manner. But if you are getting a hard time expressing the steps with And
and But
you can use *
in front of the step instead.
Scenario Outline:
This is used when we want to execute the same scenario multiple times with different data. As far as syntax is concerned there are only 3 differences from the above-discussed syntax.
- Use keyword
Scenario Outline:
instead ofScenario:
- Steps can have variables data stated as
<variableName>
- An Example Table is used at the end of the scenario which has one header row matching the
variableNames
used in Steps and more rows for data.
Each row is used for one scenario execution and values are separated by |
Scenario Outline: Check Item Type Filter
Given website page "website-url" is open
And Have a "random" user
And User logs in
When User search for item type "<itemType>"
Then System should show all "<itemType>" items
Example:
| itemType |
| bad items |
| good items |
| expired items |
Background:
When we want to execute the same steps in all scenarios within a feature file. It's better to write those steps as Background:
a rough comparison is like @BeforeEach
annotation from Junit5.
Make sure what you put in the Background:
is not related to the behavior of the scenario you are testing. So in the above example, the following can be used as Background
Background:
Given website page "website-url" is openScenario: Unauthorize admin reports access
Given Have a "non ADMIN" user
When User logs in
Then User should be able to see user Home Page
But User should not see reports sectionScenario Outline: Check Item Type Filter
Given Have a "random" user
And User logs in
When User search for item type <itemType>
Then System should show all <itemType> items
Example:
| itemType |
| bad items |
| good items |
| expired items |
(#)
In any line of feature-file, If the first non-space character is #
then that line is regarded as a code comment. Any text followed by a #
is discarded
This was a brief overview of Gherkin grammar, now let's take a look at the Step Definition
Step Definition
All text followed by any one of these keywords Given
, When
, Then
, But
And
& *
is called step
. Steps give a nice business meaning to a scenario. But the Cucumber engine needs to know what to do when it sees those steps. That is where step-definition comes into the picture.
- Step definition can be written in one of many supported languages mentioned in the previous post. I personally am aware only of Java.
- The developer needs to create one or preferably a few syntactically grouped
.java
files and add a java method for each step. This method is the step-definition. and it should have code to perform the required tasks for the step. - The dynamic values in steps (text covered between
“ “
or<>
), should be declared as method parameters in thestep definition.
- Eventually, Cucumber flattens the directory structure before running the tests. so you can place the java files anywhere, but for maintainability, try to have a meaningful package structure.
- The data from
Data Table
can be passed as a collection parameter to step definition. - The data from the
Example
table is processed in one row per scenario, so it can be passed as a scalar value in the step definition. - Step-definition class can have instance variables to share states between steps. but make sure to clean up states after you are done.
public class HomePageSteps{UserCredentials userCredentials;
HomePage homePage;@Given("^Have a \"([^\"]*)\" user$")
public void getUser(String userType) {if("random".userType){
userCredentials = userService.getCredentials(getRandomUSer());
}else if("non ADMIN".userType){
userCredentials = userService.getCredentials("User1");
}else if("ADMIN".userType){
userCredentials = userService.getCredentials("myAdmin");
}
}When("^User search for item type \"([^\"]*)\"$")
public void searchItem(String itemType) {
homePage.searchItemByType(itemType);
}}
This concludes our brief summary about the Cucumber, In the next post, we will discuss how to use Karate to do API testing.
Comments