Why we need Pico Container?
Inheritance is not possible in Cucumber step definition class. What if we don't want to create objects for dependent class in step classes?
Then how we are going to use the dependent class in step definition classes.
The solution is using Pico container for dependency injection.
1. By using Pico container we can share the states between the steps in a single feature or multiple feature file.
2.Pico Container identifies dependencies by looking at the constructors of registered step definition classes ( Constructor Injection )
Let's create simple maven project for understanding the pico container.
Below is the folder structure for our demo project.
1. Add dependency in pom.xml
Add the following dependency (latest version) in the pom.xml
<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-picocontainer -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>7.8.0</version>
<scope>test</scope>
</dependency>
2.Create two feature files like below.
Home.feature
@HomePage
Scenario: Validating the homepage
Given User opens the google website
When User is on home page
Then User should be able to enter the search key "Roses" in the
search box
Search.feature
@SearchResults
Scenario: Validating the search results
Given User is on google home page
When User enters search keyword "Roses"
Then User should be navigated to search results page "Roses"
3. Driver initialization
Base class is created with driver setup, teardown functions etc.,
BaseClass.java
package base;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class BaseClass {
public WebDriver driver;
public void setup()
{
String path = System.getProperty("user.dir");
System.setProperty("webdriver.chrome.driver",
path+"/Drivers/chromedriver.exe");
if(driver==null)
{
driver = new ChromeDriver();
}
}
public void openBaseURL()
{
driver.get("https://www.google.com");
}
public void tearDown()
{
driver.quit();
}
}
4. Context Class
Driver initialization and Page objects creation is done in context class.
Context.java
package utilities;
import org.openqa.selenium.WebDriver;
import base.BaseClass;
import pageObjects.HomePage;
import pageObjects.SearchPage;
public class Context extends BaseClass {
private HomePage homePage;
private SearchPage searchPage;
public Context()
{
setup();
}
public WebDriver getDriver()
{
return driver;
}
public HomePage getHomePage()
{
if(homePage==null)
{
homePage = new HomePage(driver);
}
return homePage;
}
public SearchPage getSearchPage()
{
if(searchPage==null)
{
searchPage = new SearchPage(driver);
}
return searchPage;
}
}
5. Step definition and page class
Now we can use context class objects in step definition classes for creating page objects and initializing driver,
by injecting Context object in constructer of step definition class. This is called constructor dependency injection.
Example:
public HomeStep(Context context)
{
this.context = context;
homePage = context.getHomePage();
}
Note : constructor should be public
Please refer the below step definition class and page class for further understanding.
HomeStep.java
package stepDefinitions;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.When;
import io.cucumber.java.en.Then;
import pageObjects.HomePage;
import utilities.Context;
public class HomeStep {
Context context;
HomePage homePage;
public HomeStep(Context context)
{
this.context = context;
homePage = context.getHomePage();
}
@Given("User opens the google website")
public void user_opens_the_google_website() {
context.openBaseURL();
System.out.println("User opens the google website\n");
}
@When("User is on home page")
public void User_is_on_home_page() {
System.out.println("User is on homepage\n");
}
@Then("User should be able to enter the search key {string} in the
search box")
public void
user_should_be_able_to_enter_the_search_key_in_the_search_box(String
searchKey) {
homePage.search(searchKey);
System.out.println("User can enter the seach key\n");
}
}
HomePage.java
package pageObjects;
import java.time.Duration;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
public class HomePage {
WebDriver driver;
WebDriverWait wait;
public HomePage(WebDriver driver){
this.driver = driver;
PageFactory.initElements(driver, this);
wait = new
WebDriverWait(this.driver,Duration.ofSeconds(1));
}
@FindBy (name ="q") WebElement searchBox;
public void search(String searchKey)
{
wait.until(ExpectedConditions.visibilityOf(searchBox));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
searchBox.clear();
searchBox.sendKeys(searchKey);
}
public void enterSearch()
{
searchBox.sendKeys(Keys.ENTER);
}
}
SearchStep.java
package stepDefinitions;
import org.testng.Assert;
import io.cucumber.java.After;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import pageObjects.HomePage;
import pageObjects.SearchPage;
import utilities.Context;
public class SearchStep {
Context context;
SearchPage searchPage;
HomePage homePage;
public SearchStep(Context context)
{
this.context = context;
searchPage = context.getSearchPage();
homePage = context.getHomePage();
}
@Given("User is on google home page")
public void User_is_on_google_home_page() {
context.openBaseURL();
System.out.println("User is on google home page\n");
}
@When("User enters search keyword {string}")
public void user_enters_search_keyword(String searchKey) {
System.out.println("User enters search keyword :
"+searchKey+"\n");
homePage.search(searchKey);
homePage.enterSearch();
}
@Then("User should be navigated to search results page {string}")
public void user_should_be_navigated_to_search_results_page(String
searchKey){
if(searchPage.getPageTitle().contains(searchKey))
{
System.out.println("User is in search results page\n");
Assert.assertTrue(true);
}
}
}
SearchPage.java
package pageObjects;
import java.time.Duration;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.WebDriverWait;
public class SearchPage {
WebDriver driver;
WebDriverWait wait;
public SearchPage(WebDriver driver){
this.driver = driver;
PageFactory.initElements(driver, this);
wait = new WebDriverWait(this.driver,Duration.ofSeconds(1));
}
@FindBy (xpath ="") WebElement Title;
public String getPageTitle()
{
return driver.getTitle();
}
}
Highlights:
Before every scenario , constructor is injected with context objects. And this can be shared within steps of the scenario, present in same or different classes.
Hope this is useful!
Happy Testing!!!