Test Driven Development (TDD)
Test Driver Development or TDD is the approach where automated test cases are created and
executed before developing the actual application.
Development involves creating the minimum amount of code to make the failed test cases pass.
Behaviour Driven Development (BDD):
Behaviour Driven Development evolved from TDD with focus to delivery of prioritised,verifiable business value by providing a common vocabulary that reduces the gap between the technical
and business sides of the project.
BDD is a technique where your specifications or test cases are written in plain English. With this approach
non-technical team members find it easy to understand the flow and collaborate more in the process of Software
Development.
What is Cucumber Tool?
Cucumber is a testing tool that supports behavior-driven development (BDD).
- BDD bridges the gap between the stakeholders and technical team through a common platform.
- Gherkin is used as the language using which the test cases are written. It is a simple format and can also be read and modified by a non-technical user.
In BDD, “Given-When-And-Then-But” is the proposed approach for writing test cases. Listed below is an example of BDD.
because of the reasons listed below
1.Cucumber is open source and therefore free to use
2.With Cucumber, you can write test scripts in multiple languages, such as java,Ruby,.Net,python, etc..
3. It is also integrates with selenium, Ruby on Rails, Watir, and other web-based Testing tools
4.Cucumber is one of the most widely used BDD tools.
Feature: I want to login into the site with valid data and Invalid data
Background:
Given I navigate to the Website
Scenario: Login as a new sign-up user with valid data
When I entered the user name
And I entered the password
And click on the sign-in button
Then validate user successfully logged-in
But log-in button is not present
Scenario: Login as a new sign-up user with invalid data
When I entered an invalid user name
And I entered the password
And click on the sign-in button
Then Error message should display
But Re-login option be available
What are Gherkin Keywords
In the above example, there are many keywords, and every keyword has its own meaning and purpose.
Let’s explain each keyword with respect to the above example.
- Feature Keyword: The feature file starts with the keyword Feature. Under feature, you can mention the feature name which is to be tested, as seen below
I want to login into the site with valid data and Invalid data
I want to login into the site with valid data and Invalid data
Feature Files:
Feature file is a file with ‘.feature’ extension which describes the feature to test in an easilyreadable descriptive language.
The feature file usually contains a feature with multiple scenarios for testing that feature.
A Feature File is an entry point to the Cucumber tests. This is a file where you will describe
your tests in Descriptive language (Like English). It is an essential part of Cucumber,
ou need to make sure that they carry the ‘.feature‘ file extension.
- Scenario Keyword: There can be more than one scenario under one feature file, and each scenario starts with the keyword Scenario, followed by the scenario name. In the below example, we can see there are two scenarios.
Scenario: Login as a sign-up user with valid data
Scenario: Login as a sign-up user with invalid data
Scenario: Login as a sign-up user with valid data Scenario: Login as a sign-up user with invalid data
- Given Keyword: Given keyword is normally used when we have to give some pre-condition in our test case as seen in the example below
Given User is on the home page of the site or
Given User is on the Log-in page of the site.
Given User is on the home page of the site or Given User is on the Log-in page of the site.
- When Keyword: When the keyword is used to perform some action, as depicted in the example below
When the user enters an email or
When the User clicks on the "Log in" button
When the user enters an email or When the User clicks on the "Log in" button
- And Keyword: There is no annotation for AND keyword. It is used to connect two statements and provides the logical AND condition between any two statements. AND can be used in combination with GIVEN, WHEN and THEN statements and used for positive assertion
When I entered my "username"
And I entered “password”
When I entered my "username" And I entered “password”
- Then Keyword: Then Keyword is used for the final outcome or for validation
Then validate the user successfully logged in Or
Then an Error message should display
Then validate the user successfully logged in Or Then an Error message should display
- But Keyword: But the keyword is used to represent negative assertions in addition to the previous statement.
- Background Keyword: If there is any repetitive step that is going to be used in every test case. We just add the repetitive step under Keyword Background. Step keep under Background would be run before every test case.
Background: Given I navigate to the Website
Background: Given I navigate to the Website
Cucumber Best Practices for Effective Testing
1. Write test scenarios as early as possible
It’s a good practice if we are ready to write test scenarios before creating test code. Developing scenarios early helps you define software behavior and understand possible problems in a better way. Once a scenario is ready and reviewed by team members who agree with it, we can start implementing the functionality. This will save time and effort and take away uncertainty later, during the development, or when your team will run acceptance tests.
2. Features and Scenarios
A feature is a product functionality, whereas a scenario is the specification of behavior.
Feature file:
- Feature file should be specific to the page, meaning if you have to cover the login scenario we should create a “login.feature”
- A single feature file can contain multiple scenarios
- Avoid mixing feature files
- Every feature should be ready to be executed alone
Scenario:
To describe the scenarios, Gherkin keywords are used: Given, When, Then, But and And During writing the scenario we have to make sure we should use keywords in an appropriate way.
See below an example of a poorly written scenario
Scenario: As an existing user, I want to log in successfully
Given the user is on the Home page
When the user clicks on the login link on Home Page
And the user can see the login screen
And the user enters his username and password
And the user is able to click on the login button
Then the user is logged in successfully
And the successful login message is displayed
A better way to write the same above scenario with fewer lines is as follows. It is best to avoid details that don’t contribute much.
Scenario: As an existing user, I want to log in successfully. Given the user is on the Home page When the user navigates to the Login page And the user enters the username and password Then the successful login message is displayed
3. Use Background
It is always the best practice to put steps that are repeated in every scenario into the Background. The background step is run before every scenario.
Ensure that you don’t put too many steps in there, as your scenarios may become hard to understand. Given below is an example.
Feature: I want to login into the site with valid and invalid data Background: Given I navigate to the Website Scenario: Login as a new sign-up user with valid data When I entered a valid credential | email| validpassword | | qatubeupdate@yopmail.com | 12345 | When the user clicks on the sign-in button Then Validate the title after login Scenario: Login with invalid data by entering an invalid password When I entered an invalid credential | email | invalidpassword | | qatubeupdate@yopmail.com | 123456 | When the user clicks on the sign-in button Then Error message should display | errormessage | | Authentication failed |
4. Try to re-use step definitions
It’s best practice to reuse the step definitions that you frequently use in various scenarios. For example, “Given: user navigate to the Website” can be one common step that we need in every scenario. So we can reuse this step.
Reusing the steps improves the maintainability, just in case there are any changes, you need to update in a single step.
Ensure the language/words are consistent if you want to re-use the step. In the below example, the steps are the same but the words (casing) are not consistent.
Click and click are considered different because of the casing.
Given (“Click on ‘Sign In link’ on the Home Page”)
Given (“click on ‘Sign In link’ on the Home Page”)
5. Use a Data Table
It’s recommended to use Data Table to store the data. You can give data as parameters within the step but once you have a large set of data. It is not feasible to relinquish all data as parameters. It’s better to use a data table once you have a large set of data.
A data table is used to inject data at the step level. The below example illustrates the steps for “I entered valid credential
Feature: I want to login into the site with valid and invalid data Background: Given I navigate to the Website @SmokeTest Scenario: Login as a new sign-up user with valid data When I entered valid credential | email | validpassword |title| | qatubeupdate1@yopmail.com | 12345 | Home | | qatubeupdate2@yopmail.com | 12345 | Home | | qatubeupdate3@yopmail.com | 12345 | Home | | qatubeupdate4@yopmail.com | 12345 | Home | When User click on sign-in button Then Validate the title after login
6. Use a Scenario outline
Scenario outline injects the info at the scenario level rather than the step level. Scenario outline followed by the keyword.
Feature: I want to login into the site with valid and invalid data Scenario Outline: Login Validation Given I navigate to the Website When I enter "<email>" and "<validpassword>" to login Page And User click on sign-in button Then Validate the "<title>" after login Example: | email | validpassword |title| | qatubeupdate@yopmail.com | 12345 | Home |
7. Use of Tags
Using tags could be the best practice once we want to run a bunch of test cases. There will be the case that we don’t want to execute all test cases in a single run or we would like to execute a group of the test cases. So best practice is to configure the test case by putting Tags on it. They are marked with @ followed by some text.
For example, a group of smoke test cases and sanity tests is created. You can put a tag over the scenario like @SmokeTest, @SanityTest, @RegressionTest, etc
Feature: I want to login into the site with valid and invalid data Background: Given I navigate to the Website @SmokeTest Scenario: Login as a new sign-up user with valid data When I entered a valid credential | email | validpassword | | qatubeupdate@yopmail.com | 12345 | When a user clicks on sign-in button Then Validate the title after login @SanityTest Scenario: Login with invalid data by entering an invalid password When I entered an invalid credential | email | invalidpassword | | qatubeupdate@yopmail.com | 123456 | When the user clicks on the sign-in button Then Error message should display | errormessage | | Authentication failed |
8. Map your scenario with the requirement
It’s a best practice to provide the required number (#Jira story id) after the scenario in the feature file. If any scenario fails then tracking the failed requirement from the execution report becomes easier (See below test case execution screenshot)
For example, in lines #6, and #14 of the code below, the required number is specified for better tracking.
Feature: I want to login into the site with valid and invalid data Background: Given I navigate to the Website @SmokeTest Scenario: Login as a new sign-up user with valid data: QA-135, QA-156 When I entered a valid credential | email | validpassword | | qatubeupdate@yopmail.com | 123451 | When the user clicks on the sign-in button Then Validate the title after login @SanityTest Scenario: Login with invalid data by entering the invalid password: QA-569, QA-281 When I entered an invalid credential | email | invalidpassword | | qatubeupdate@yopmail.com | 123456 | When the user clicks on the sign-in button Then Error message should display | errormessage | | Authentication failed |
Test Result: The result of the above test can be seen below, where in the Smoke Test fails while the Sanity Test passes. Here, using the JIRA Story ID can be used to track the failed tests and debug
9. Avoid Conjunctive Steps
While writing the feature, it is best to avoid conjunctive steps. When you find a Cucumber step that contains two actions in conjunction with an “and”, you should break it into two steps keeping one action per step. This makes the steps more modular and increases reusability. This is not a general rule but a best practice.
10. Write in a declarative way, not Imperative
Scenarios should be written in a way the user would describe them. Beware of scenarios that only describe clicking links and entering data in form fields, or of steps that contain code. This is not a feature description. Declarative features are realistic, compendious, and contain highly maintainable steps.
Example of Declarative Scenario:
Scenario: Verify login Given user navigate to the Website When user enters credentials Then the user clicks on the sign-in button Then validate the title after login
Example of Imperative Scenario:
Scenario: Verify login Given I navigate to the Website When I enter “username” When I enter “password” When I check the “Remember me” check box Then the user clicks on the sign-in button Then Validate the title after login
11. Rules for writing Scenarios in Cucumber
Test scenarios should be written in a way that is easy to understand and clear for every team member. Below are some common recommendations
- Proper use of correct grammar and spelling
- Step definitions should not end with periods, commas, and other punctuation marks
- Avoid jargon
- Use correct punctuation
When dealing with behavior-driven automation, there are a ton of rules that you can use as guiding principles, the main core thing we have to keep in mind is one should properly use keywords GIVEN, WHEN, and THEN. Remember all the above points when we write test cases using the BDD framework.
What is Step Definition?
A Step Definition is a small piece of code with a pattern attached to it or in other words aStep Definition is a java method in a class with an annotation above it. An annotation followed
by the pattern is used to link the Step Definition to all the matching Steps,
and the code is what Cucumber will execute when it sees a Gherkin Step. Cucumber finds the Step
Definition file with the help of Glue code in Cucumber Options.
Gherkin code:
@Given("^User is on Linkedin Welcome page$")
public void user_is_on_Linkedin_Welcome_page() throws Throwable {
// Write code here that turns the phrase above into concrete actions
assertTrue(driver.getTitle().contains("Welcome! | LinkedIn"));
}
@When("^user mouse over on profile image$")
public void user_mouse_over_on_profile_image() throws Throwable {
// Write code here that turns the phrase above into concrete actions
act=new Actions(driver);
act.moveToElement(page.progfileImage).perform();;
}
@When("^click on Signout link$")
public void click_on_Signout_link() throws Throwable {
// Write code here that turns the phrase above into concrete actions
act.moveToElement(page.signout_link).click().build().perform();
}
@Then("^user is loggedout from linkedin$")
public void user_is_loggedout_from_linkedin() throws Throwable {
// Write code here that turns the phrase above into concrete actions
assertTrue(driver.getTitle().contains("Signed Out | LinkedIn"));
}
-------------------------------------------------------------------
3. Test Runner file
Cucumber uses Junit framework to run
As Cucumber uses Junit we need to have a Test Runner class. This class will use the Junitannotation @RunWith(),
which tells JUnit what is the test runner class. It more like a starting point for Junit to
start executing your tests.
In the src folder create a class called TestRunner.
First import statement ‘org.junit.runner.RunWith‘ imports @RunWith annotation from the Junit class.
@RunWith annotation tells JUnit that tests should run using Cucumber class present in ‘Cucumber.api.junit‘ package.
Second import statement io.cucumber.junit.CucumberOptions‘ imports the @CucumberOptions annotation.
This annotation tells Cucumber a lot of things like where to look for feature files, what reporting system to use
and some other things also
What is Cucumber Options ?
In layman language @CucumberOptions are like property file or settings for your test.Basically @CucumberOptions enables us to do all the things that we could have done
if we have used cucumber command line. This is very helpful and of utmost importance if we are using IDE such eclipse only to execute our project. You must have noticed that we set few options in the ‘TestRunner’ class
Run the Cucumber Test
Now we are all set to run the first Cucumber test. Right Click on TestRunner class and Click Run As > JUnit Test.
Dry Run
dryRun option can either set as true or false. If it is set as true, it means that Cucumber
will only checks that every Step
mentioned in the Feature File have corresponding code written in Step Definition file or not.
So in case any of the function is missed in the Step Definition for any Step in Feature File,
it will give us the message.
For practice just add the code ‘dryRun = true‘ in TestRunner class:
TestRunner Class
package cucumberTest;
import org.junit.runner.RunWith;
import io.cucumber.junit.CucumberOptions;
import io.cucumber.junit.Cucumber;
@RunWith(Cucumber.class)
@CucumberOptions(
features = "Feature"
glue={"stepDefinition"}
dryRun = true
)
public class TestRunner {
}
======================
Monochrome
This option can either set as true or false. If it is set as true, it means that the console
output for the Cucumber test are much more readable. And if it is set as false, then the console
output is not as readable as it should be. For practice just add the code ‘monochrome = true‘ in TestRunner class:
package cucumberTest;
import org.junit.runner.RunWith;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
@RunWith(Cucumber.class)
@CucumberOptions(
features = "Feature"
,glue={"stepDefinition"}
,monochrome = false
)
public class TestRunner {
}
================================================
Features
Features Options helps Cucumber to locate the Feature file in the project folder structure. You must have notices that we have been specifying the Feature Option in the TestRunner class since the first chapter. All we need to do is to specify the folder path and Cucumber will automatically find all the ‘.features‘ extension files in the folder. It can be specified like:
features = “Feature“
Or if the Feature file is in the deep folder structure
features = “src/test/features“
======================================
Glue
It is almost the same think as Features Option but the only difference is that it helps Cucumber to locate the Step Definition file. Whenever Cucumber encounters a Step, it looks for a Step Definition inside all the files present in the folder mentioned in Glue Option. It can be specified like:
glue = “stepDefinition“
Or if the Step Definition file is in the deep folder structure
glue = “src/test/stepDeinition“
================================================
plugin
plugin Option is used to specify different formatting options for the output reports. Various options that can be used as for-matters are:
Pretty: Prints the Gherkin source with additional colours and stack traces for errors. Use below code:
plugin = {“pretty“}
HTML: This will generate a HTML report at the location mentioned in the for-matter itself. Use below code:
plugin = {“html:Folder_Name“}
JSON: This report contains all the information from the gherkin source in JSON Format. This report is meant to be post-processed into another visual format by 3rd party tools such as Cucumber Jenkins. Use the below code:
plugin = {“json:Folder_Name/cucumber.json“}
JUnit: This report generates XML files just like Apache Ant’s JUnit report task. This XML format is understood by most Continuous Integration servers, who will use it to generate visual reports. use the below code:
plugin = { “junit:Folder_Name/cucumber.xml“}
==============================================
tags: we can run the cucumber test using tags. under cucumber options specify the tags={"@tagname"}
============================================
Scenario Outline – This is used to run the same scenario for 2 or more different set of test data.
E.g. In our scenario, if you want to register another user you can data drive the same scenario twice.Examples – All scenario outlines have to be followed with the Examples section.
This contains the data that has to be passed on to the scenario.
Examples:
| username | password |
| testuser_1 | Test@153 |
| testuser_2 | Test@153 |
Note: The table must have a header row corresponding to the variables in the Scenario Outline steps.
=======================================
Data Tables in Cucumber
Scenario: Successful Login with Valid Credentials
Given User is on Home Page
When User Navigate to LogIn Page
And User enters Credentials to LogIn
| testuser_1 | Test@153 |
Then Message displayed Login Successfully
StepDefinitionFile:
The implementation of the above step will belike this:
@When("^User enters Credentials to LogIn$")
public void user_enters_testuser__and_Test(DataTable usercredentials) throws Throwable {
//Write the code to handle Data Table
List<List<String>> data = usercredentials.asLists();
//This is to get the first data of the set (First Row + First Column)
driver.findElement(By.id("log")).sendKeys(data.get(0).get(0));
//This is to get the first data of the set (First Row + Second Column)
driver.findElement(By.id("pwd")).sendKeys(data.get(0).get(1));
driver.findElement(By.id("login")).click();
}
Data Tables in Cucumber are quite interesting and can be used in many ways. DataTables are also used to handle large amount of data. They are quite powerful but not the most intuitive as you either need to deal with a list of maps or a map of lists. Most of the people gets confused with Data tables & Scenario outline, but these two works completely differently.
===========================================
Difference between Scenario Outline & Data Table
Scenario Outline:
This uses Example keyword to define the test data for the ScenarioThis works for the whole test
Cucumber automatically run the complete test the number of times equal to the number of data in the Test Set
Test Data:
No keyword is used to define the test data
This works only for the single step, below which it is defined
A separate code is need to understand the test data and then it can be run single or multiple times but again just for the single step,
not for the complete test
================================================
Maps in Data Tables:
Maps in Data Tables can be used if different ways. Headers can also be defined for the data tables. A same step can be executed multiple times with different set of test data using Maps.Maps in Data Tables with Header
In the previous chapter of Data Tables in Cucumber, we pass Username & Password without Header, due to which the test was not much readable. What if there will be many columns. The basic funda of BDD test is to make the Test in Business readable format, so that business users can understand it easily. Setting Header in Test data is not a difficult task in Cucumber. take a look at a below Scenario.
Feature file scenario
Scenario: Successful Login with Valid Credentials
Given User is on Home Page
When User Navigate to LogIn Page
And User enters Credentials to LogIn
| Username | Password |
| testuser_1 | Test@153 |
Then Message displayed Login Successfully
The implementation of the above step will be like this:
@When("^User enters Credentials to LogIn$")
public void user_enters_testuser_and_Test(DataTable usercredentials) throws Throwable {
//Write the code to handle Data Table
List<Map<String,String>> data = usercredentials.asMaps(String.class,String.class);
driver.findElement(By.id("log")).sendKeys(data.get(0).get("Username"));
driver.findElement(By.id("pwd")).sendKeys(data.get(0).get("Password"));
driver.findElement(By.id("login")).click();
}
================================================
Why Cucumber Hooks?
Hooks are blocks of code that run before or after each scenario in the Cucumber execution cycle. This allows us to manage the code workflow better and helps to reduce code redundancy.
Hooks can be defined anywhere in the project or step definition layers using the methods @Before and @After. They are typically used for setup and tear-down of the environment before and after each scenario.
@Before - Before hooks run before the first step of each scenario. This is commonly used for prerequisite steps that need to be performed before the actual test scenario. For example, this can be as follows.
1. Initialize a web driver: This is the most common use case. We need to initialize the driver once before launching the test.
// Define driver
WebDriver driver;
2. Establish DB connections: Application may require access to test data at the start of the test. A couple of examples could be -
> read data through any external sources like DB.
3. To set up test data: Application may require to access test data at the start of the test. A couple of examples could be -
> read date from the property file
> read data through any external sources like DB, XL, JSON, etc.
4. To set browser cookies: Certain times, the application requires to set some cookies to achieve the functional goal.
5. Navigate to default page: Whenever a test is launched, it may need to navigate to the default application URL.
driver.get("<<APP URL >> /admin");
Annotated method style:
@Before
public void setup() {
// Do something before each scenario
}
@After - After hooks run after the last step of each scenario, even when steps are failed, undefined, pending, or skipped. This is commonly used for steps that need to be performed after the actual scenario gets executed. For example, this can be as follows.
1. Quit the web driver: This is most commonly used. After each test, we are supposed to kill the browser in order to make tests independent.
//Quit driver
driver.quit();
2. To close DB connections: If we have established the DB connection at the beginning of the test, then it is advisable to terminate at the end of the tests.
3. To clear the test data/browser cookies: As @After hook will execute at the end of each test, we have clean up activity here.
4. Sign out from the application: Signing out from the application is really essential in order to make tests independent.
5. Take screenshots for fail/pass scenarios: In order to make sure the test runs correctly, We always need to take a screenshot in case of any failure.
Annotated method style:
@After
public void teardown(Scenario scenario) {
// Do something after each scenario
}
Run Hooks with Single Scenario
- Hooks execute before and after scenario
package com.blog.common; import org.openqa.selenium.WebDriver; public class BaseClass { public String baseURL = "http://automationpractice.com"; public WebDriver driver; }
Login Feature File
Feature: Login Feature As an authenticated I want to login to application So that I can access application feature Scenario: Check valid login Given user is on Login Page When user has provided valid credentials Then user should be able to login
StepDefinition for Login featureFile
package com.blog.stepdefs; import org.openqa.selenium.By; import org.openqa.selenium.Keys; import org.testng.Assert; import com.blog.common.BaseClass; import cucumber.api.java.en.And; import cucumber.api.java.en.Given; import cucumber.api.java.en.Then; import cucumber.api.java.en.When; public class LoginSteps extends BaseClass { private BaseClass base; public LoginSteps(BaseClass base) { this.base = base; } @Given("^user is on Login Page$") public void user_is_on_Login_Page() throws Throwable { base.driver.get(base.baseURL+"/index.php?controller=authentication&back=my-account"); } @When("^user has provided valid credentials$") public void user_has_provided_valid_credentials() throws Throwable { base.driver.findElement(By.id("email")).sendKeys("blog.cucumber@gmail.com"); base.driver.findElement(By.id("passwd")).sendKeys("Cucumber@blog"); base.driver.findElement(By.id("SubmitLogin")).click(); } @Then("^user should be able to login$") public void user_should_be_able_to_login() throws Throwable { String exp_message = "Welcome to your account. Here you can manage all of your personal information and orders."; String actual = base.driver.findElement(By.cssSelector(".info-account")).getText(); Assert.assertEquals(exp_message, actual); }
---------------------------------------------------------------
Hooks Implementation:
package com.blog.stepdefs; import java.util.concurrent.TimeUnit; import org.openqa.selenium.By; import org.openqa.selenium.chrome.ChromeDriver; import com.blog.common.BaseClass; import cucumber.api.java.After; import cucumber.api.java.Before; public class Hook extends BaseClass{ private BaseClass base; public Hook(BaseClass base) { this.base = base; } @Before public void initDriver() { System.out.println("Open browser"); System.setProperty("webdriver.chrome.driver", "lib/chromedriver 3"); base.driver = new ChromeDriver(); base.driver.manage().window().maximize(); base.driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); } @After public void teardown() { System.out.println("Close browser"); base.driver.quit(); } }
---------------------------------------------
- It is not recommended to have too many print statements in the Automation code as it slows down the execution. Here it has been added just for the explanation purpose.
- It’s always recommended to place the chrome driver in the project folder itself. For that, create a lib folder in the project and place the chrome driver file in the folder. The project structure will look like below.
Execution
To execute the above code, right-click login.feature file → Run As → Cucumber Feature. On executing the login.feature file it will show below output in the console. Here I have executed with Chrome.
Run Hooks with Multiple Scenarios
- As stated earlier, Scenario Hooks execute before and after every scenario. In the below example, both the Before and After hooks are executed two times for two scenarios.
Execution Order:
Feature: Login Feature As an authenticated I want to login to application So that I can access application feature Scenario: Check valid login Given user is on Login Page When user has provided valid credentials Then user should be able to login Scenario: SearchProduct Given user is on Login Page When user has provided valid credentials Then user search for the product
------------------------------------------------------------------------------
Output:
How to set the Priority of Cucumber Hooks?
- Priority in Cucumber is almost the same as a priority in TestNG.
- Cucumber executes Hooks in a certain order but there is a way to change the order of the execution according to the need for the test.
- @Before(order = int): This runs in increment order, means value 0 would run first and 1 would be after 0
- @After(order = int): This runs in decrements order, which means the opposite of @Before. Value 1 would run first and 0 would be after 1.
package com.blog.stepdefs; import java.util.concurrent.TimeUnit; import org.openqa.selenium.By; import org.openqa.selenium.chrome.ChromeDriver; import com.blog.common.BaseClass; import cucumber.api.java.After; import cucumber.api.java.Before; public class Hook extends BaseClass{ private BaseClass base; public Hook(BaseClass base) { this.base = base; } @Before(order = 0) public void initDriver() { System.out.println("Open browser"); System.setProperty("webdriver.chrome.driver", "lib/chromedriver 3"); base.driver = new ChromeDriver(); base.driver.manage().window().maximize(); base.driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); } @Before(order = 1) public void maximizeWindow() { System.out.println("Maximize window"); base.driver.manage().window().maximize(); } @After(order = 1) public void signOut() { System.out.println("Sign out from app"); base.driver.findElement(By.linkText("Sign out")).click(); } @After(order = 0) public void teardown() { System.out.println("Close browser"); base.driver.quit(); } }
The execution order of Hooks
- The above diagram explains the order of execution.
- Execution order will be Before Hook 0 -> Before Hook 1 -> Scenario -> After Hook 1 -> After Hook 0.
- Before the first step of each scenario, Before hooks will be run. Execution order is the same order of which they are registered. After the last step of each scenario, After hooks will be run. It doesn't matter even when there are failing, undefined, pending or skipped steps.
- The above diagram explains the order of execution.
- Execution order will be Before Hook 0 -> Before Hook 1 -> Scenario -> After Hook 1 -> After Hook 0.
- Before the first step of each scenario, Before hooks will be run. Execution order is the same order of which they are registered. After the last step of each scenario, After hooks will be run. It doesn't matter even when there are failing, undefined, pending or skipped steps.
Tagged Hooks
In the above topic explained how hooks are executed before or after each scenario. Tagged hooks are almost similar but the only difference is that they are executed before and after the specified tag.
If we have different prerequisites for different scenarios then we need to have different hooks for different scenarios. Let’s say we have two different tags smoke and regression and we want to perform different operations based on the tag then such things can be achieved through tagged hooks.
In the below feature file, two scenarios are tagged with @Smoke and one tagged with @Regression
Login.Feature
Feature: Login Feature As an authenticated I want to login to application So that I can access application feature @Smoke Scenario: Check valid login Given user is on Login Page When user has provided valid credentials Then user should be able to login @Smoke Scenario: SearchProduct Given user is on Login Page When user has provided valid credentials Then user search for the product @Regression Scenario: Check invalid login Given user is on Login Page When user has provided invalid credentials Then user should not be able to login
package com.blog.stepdefs; import java.util.concurrent.TimeUnit; import org.openqa.selenium.By; import org.openqa.selenium.chrome.ChromeDriver; import com.blog.common.BaseClass; import cucumber.api.java.After; import cucumber.api.java.Before; public class Hook extends BaseClass{ private BaseClass base; public Hook(BaseClass base) { this.base = base; } @Before public void initDriver() { System.out.println("Open browser"); System.setProperty("webdriver.chrome.driver", "lib/chromedriver 3"); base.driver = new ChromeDriver(); base.driver.manage().window().maximize(); base.driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); } @After("@Smoke") public void signOut() { System.out.println("Sign out from app"); base.driver.findElement(By.linkText("Sign out")).click(); } @After("@Regression,@Smoke") public void quitBrowser() { System.out.println("Close browser"); base.driver.quit(); } }
================================================================================
TestRunner.java
--------
package com.blog.runner; import org.junit.runner.RunWith; import cucumber.api.junit.Cucumber; import cucumber.api.CucumberOptions; @RunWith(Cucumber.class) @CucumberOptions(features= "src/test/java/com/blog/features", glue= {"com.blog.stepdefs"}, tags = {"@Smoke,@Regression"}) public class TestRunner { }
--------
OUTPU:
Setting up Maven BDD Cucumber selenium framework:
Step1:
1)Instal JDK 8 or JDK 11
2)download Eclipse/Intellij
3)set below paths in environment variables
i)java home
ii)Maven home
4)Install Cucumber JVM Eclipse plugin from help market place in eclipse orintellij cucumber plugin
- In Eclipse, go to Help → Install new software
- On the Available Software popup, enter the URL “ http://cucumber.github.com/cucumber-eclipse/update-site ” in the Work with field.
- You will see “Cucumber Eclipse Plugin” displayed in the filter; select the checkbox and click Next, and you will navigate to the Install Details popup. Click Next to proceed further.
- Accept the license in the Review License pop-up and click Finish.
Why Maven?
Maven is a automation build tool and is widely used for Java projects. It is mainly used in managing dependencies through pom.xml. Suppose you want to upgrade the JAR files and in your project you are using version 1.25 for Cucumber-Java dependency. You need to upgrade to the latest version. With the use of Maven, it’s easy to upgrade the version.
Set up your Maven project
Step 2: On the new Maven Project pop-up, select the checkbox to create your project at the default location OR you can also browse and set a new location of your choice. Click on Next to proceed.
Step 3: On the next screen, by default the Group ID and Artifact ID org.apache.maven.archetypes maven-archetypes-quickstart 1.1 is selected. Click on Next to proceed.
Step 4: In the next screen, you will have to mention a Group ID and Artifact ID of your own choice; this is the name of your Maven project. Once you click the Finish button, a Maven project will be created in Eclipse
As you can see, there is a pom.xml file created in your Maven project. This file consists of the Group ID and Artifact ID you entered, and by default it consists of dependency for JUnit. Refer to the screenshot below.
Step 5: Now, in order to build a Selenium-Cucumber framework for us to work with, we need to add dependency for Selenium and Cucumber in pom.xml, which is somewhat similar to adding JAR files. We will be needing dependencies of the following:
Selenium-java
Cobertura
Cucumber-jvm-deps
Cucumber-reporting
Gherkin
JUnit
Mockito-all-1.10.19
Cucumber-core
Cucumber-java
Cucumber-junit
Note: Make sure the versions on Cucumber-java, Cucumber -junit and Cucumber-core are the same, i.e., if you are using Cucumber-java-1.2.5 make sure the versions of the other two dependencies are the same.
Step 6: To add dependencies for the above, you should refer to https://mvnrepository.com/. After adding dependencies for Cucumber and Selenium, the pom.xml file will look like this:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>Cucumber_Selenium</groupId> <artifactId>Cucumber_Selenium</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>Cucumber_Selenium</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>4.16.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>3.7.0</version> </dependency> <dependency> <groupId>info.cukes</groupId> <artifactId>cucumber-java</artifactId> <version>1.2.5</version> </dependency> <dependency> <groupId>info.cukes</groupId> <artifactId>cucumber-jvm-deps</artifactId> <version>1.0.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>info.cukes</groupId> <artifactId>cucumber-junit</artifactId> <version>1.2.5</version> <scope>test</scope> </dependency> <dependency> <groupId>com.vimalselvam</groupId> <artifactId>cucumber-extentsreport</artifactId> <version>3.0.2</version> </dependency> <dependency> <groupId>com.aventstack</groupId> <artifactId>extentreports</artifactId> <version>3.1.2</version> </dependency> </dependencies> </project>
Create HTML reports in Cucumber
Imagine that you have to share the test reports with your client and senior management; in that case you will need a shareable HTML report which you can share after executing your tests.
You can achieve this by following some very simple steps.
Create an HTML report by adding a plugin to testrunner.java class
Step 1: In your testrunner.java class, add a plugin inside @CucumberOptions to format your test results into the HTML format.
plugin = { "pretty", "html:target/htmlreports" }
In order to set the path for the reports, we have to give a path in the project. To make this easier, the path is target/htmlreports.
Step 2: Now save the testrunner.java class and execute it. On execution, you will see that the folder htmlreports is created inside the target folder.
Step 3: Access the folder and look for the index.html file; that is the file which contains the test results in HTML format.
Step 4: Open the index.html to view the report. The report created would be similar to the image below.
Create HTML report by using extent-reports
We have already seen how to create an HTML test report, but with the help of extent reports we can create more well-organized and detailed reports.
Step 1: To implement extent report, we need to add two dependencies to the pom.xml and update the project after adding the dependency.
Cucumber-extentsreport
extentreports
The dependencies for the above would be like this:
<dependency> <groupId>com.vimalselvam</groupId> <artifactId>cucumber-extentsreport</artifactId> <version>3.0.2</version> </dependency> <dependency> <groupId>com.aventstack</groupId> <artifactId>extentreports</artifactId> <version>3.1.2</version> </dependency>
Step 2: Add a new folder to the project. Eg. “config” by right clicking the project folder → New → Folder → Config. Now we have to add an XML file to this folder. This XML file states the theme of the report, title, etc. The report.xml file would be like this:
<?xml version="1.0" encoding="UTF-8"?> <extentreports> <configuration> <!-- report theme --> <!-- standard, dark --> <theme>standard</theme> <!-- document encoding --> <!-- defaults to UTF-8 --> <encoding>UTF-8</encoding> <!-- protocol for script and stylesheets --> <!-- defaults to https --> <protocol>https</protocol> <!-- title of the document --> <documentTitle>Selenium Cucumber Framework</documentTitle> <!-- report name - displayed at top-nav --> <reportName>Functional Testing report</reportName> <!-- global date format override --> <!-- defaults to yyyy-MM-dd --> <dateFormat>yyyy-MM-dd</dateFormat> <!-- global time format override --> <!-- defaults to HH:mm:ss --> <timeFormat>HH:mm:ss</timeFormat> <!-- custom javascript --> <scripts> <![CDATA[ $(document).ready(function() { }); ]]> </scripts> <!-- custom styles --> <styles> <![CDATA[ ]]> </styles> </configuration> </extentreports>
package Runner; import java.io.File; import org.junit.AfterClass; import org.junit.runner.RunWith; import com.cucumber.listener.ExtentCucumberFormatter; import com.cucumber.listener.Reporter; import cucumber.api.CucumberOptions; import cucumber.api.junit.Cucumber; @RunWith(Cucumber.class) @CucumberOptions( features ="src/test/java/features" ,glue= "seleniumgluecode", plugin = { "com.cucumber.listener.ExtentCucumberFormatter:target/cucumber-reports/report.html"}, monochrome = true ) public class testrunner { @AfterClass public static void writeExtentReport() { Reporter.loadXMLConfig(new File("config/report.xml")); } }
The report created will have a heading, graph of the test results, detailed results for all features executed, and you can also filter the test results with the status Pass/Fail by clicking the Status menu.
Command line execution
Executing your Cucumber tests from Eclipse is very easy, but you can also execute them through the command line. The steps to execute the tests through the command line are as follows:
- Open the terminal in your system and navigate to your project directory.
- Since we have already added a Maven dependency through pom.xml, we can execute the test using the simple command mvn test.
- In case you have a large number of feature files added to your project, and you only want to execute a smoketest.feature file, you can use the command mvn test -Dcucumber.options=”src/test/java/Features/smoketest.feature.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.