Dependency Injection in Cucumber using Pico-Container

HOME

In this tutorial, we will use the constructor injection technique to share web driver instances in multiple step definitions using PicoContainer.

Why do we need Dependency Injection in Cucumber?

A new Framework is built that contains several Page Objects, Step Definitions, Feature files, and Helper Classes. Eventually, new Feature Files will be added that contain the steps that are already present in the existing Step Definition files. In this case, we will prefer to use the existing Step Definitions instead of creating new ones. But, Cucumber does not support Inheritance means it does not allow to extend classes that contain Step Definitions or Hooks (@After, @Before, etc.). Now, Dependency Injection comes into the picture.

In Cucumber, if we want to share state between multiple step definition files, we will need to use dependency injection (DI). There are several options: PicoContainer, Spring, OpenEJB, etc. If you’re not already using DI, then it is recommended to use PicoContainer. Otherwise, use the one that’s already in use, because you should only have one.

To use PicoContainer, add the following dependency to the POM.xml

<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-picocontainer</artifactId>
    <version>7.0.0</version>
    <scope>test</scope>
</dependency>

Let me explain this with the help of an example.

Imagine there are 2 feature files. These feature files are using the same browser initialization and website. Now, instead of for creating the browser initialization twice for 2 feature files, why not create a Common Class and mention these details in that class and using DI, call this class in the main Step Definition classes.

Feature File 1 – HomePage.feature

Feature: Home page validation
  
Background:
   Given User Navigates to HRM login page
   And User login with valid credentials
 
   @ValidQuickLaunch
   Scenario Outline: Login with valid credentials to check QuickLanuch options  
     
   When User is in Dashboard page
     Then there are valid QuickLaunch options '<options>'
         
    Examples: 
        | options                  |
        | Assign Leave             |
        | Leave List               |
        | Timesheets               |
 
     
    @ValidLegendOptions    
    Scenario Outline: Login with valid credentials to check Manu Options 
     
   When User is in Dashboard page
     Then there are valid Legend options '<legendOptions>'
         
    Examples: 
        | legendOptions               |
        | Not assigned to Subunits    |
        | Administration              |
        | Client Services             |

Feature File 2 – LoginPage.feature

Feature: Login to HRM Application 
  
   @ValidCredentials
   Scenario: Login with valid credentials
      
    Given User is on Home page
    When User enters username as "Admin"
    And User enters password as "admin123"
    Then User should be able to login sucessfully

Next, create a new class that holds the common data. For example:

public class ApplicationHooks {

	private WebDriver driver;

	@Before
	public void setUp() {
		setDriver();
	}

	public void setDriver() {

		WebDriverManager.chromedriver().setup();
		driver = new ChromeDriver();
		driver.manage().window().maximize();
		driver.get("https://opensource-demo.orangehrmlive.com/");
	}

	public WebDriver getDriver() {
		return driver;
	}

	@After
	public void tearDown() {
		getDriver().quit();
	}
}

Then, in each of your step definition files that you want to use this common data, you can add a constructor that takes StepData as an argument. This is where the injection occurs. For example:

LoginDefinition

public class LoginDefinition {

	private ApplicationHooks hooks;

	public LoginDefinition(ApplicationHooks hooks) {

		this.hooks = hooks;
	}

	@Given("User is on Home page")
	public void userOnHomePage() {

		System.out.println("Home Page is opened");
	}

	@When("User enters username as {string}")
	public void entersUsername(String userName) throws InterruptedException {

		System.out.println("Username Entered");
		hooks.getDriver().findElement(By.name("txtUsername")).sendKeys(userName);

	}

	@When("User enters password as {string}")
	public void entersPassword(String passWord) throws InterruptedException {

		System.out.println("Password Entered");
		hooks.getDriver().findElement(By.name("txtPassword")).sendKeys(passWord);

		hooks.getDriver().findElement(By.id("btnLogin")).submit();
	}

	@Then("User should be able to login sucessfully")
	public void sucessfullLogin() throws InterruptedException {

		String newPageText = hooks.getDriver().findElement(By.id("welcome")).getText();
		System.out.println("newPageText :" + newPageText);
		Assert.assertTrue(newPageText.contains("Welcome"));

	}
}

HomeDefinition

public class HomePageDefinition {

	ApplicationHooks hooks;

	public HomePageDefinition(ApplicationHooks hooks) {
		this.hooks = hooks;
	}

	@Given("User Navigates to HRM login page")
	public void userOnHomePage() {

		System.out.println("HRM login Page is opened");
	}

	@Given("User login with valid credentials")
	public void entersCredentials() throws InterruptedException {

		hooks.getDriver().findElement(By.name("txtUsername")).sendKeys("Admin");
	hooks.getDriver().findElement(By.name("txtPassword")).sendKeys("admin123");
		hooks.getDriver().findElement(By.id("btnLogin")).submit();

	}

	@When("User is in Dashboard page")
	public void verifyDashboardPage() {

		String dashboardTitle = hooks.getDriver().findElement(By.id("welcome")).getText();
		Assert.assertTrue(dashboardTitle.contains("Welcome"));

	}

	@Then("there are valid QuickLaunch options {string}")
	public void verifyQuickLinks(String options) throws InterruptedException {

		switch (options) {
		case "Assign Leave":
			String linkOne = hooks.getDriver()
					.findElement(By.xpath(
							"//*[@id='dashboard-quick-launch-panel-menu_holder']/table/tbody/tr/td[1]/div/a/span"))
					.getText();
			Assert.assertEquals(linkOne, options);

			break;
		case "Leave List ":
			String linkTwo = hooks.getDriver()
					.findElement(By.xpath(
							"//*[@id='dashboard-quick-launch-panel-menu_holder']/table/tbody/tr/td[2]/div/a/span"))
					.getText();
			Assert.assertEquals(linkTwo, options);
			Thread.sleep(1000);
			break;

		case "Timesheets":
			String linkThree = hooks.getDriver()
					.findElement(By.xpath(
							"//*[@id='dashboard-quick-launch-panel-menu_holder']/table/tbody/tr/td[3]/div/a/span"))
					.getText();
			Assert.assertEquals(linkThree, options);
			break;

		default:
			break;
		}

	}

	@Then("there are valid Legend options {string}")
	public void verifyMenuOptions(String options) throws InterruptedException {

		switch (options) {
		case "Not assigned to Subunits":
			String linkOne = hooks.getDriver()
					.findElement(
							By.xpath("//*[@id='div_legend_pim_employee_distribution_legend']/table/tbody/tr[1]/td[2]"))
					.getText();
			Assert.assertEquals(linkOne, options);
			break;

		case "Administration":
			String linkTwo = hooks.getDriver()
					.findElement(
							By.xpath("//*[@id='div_legend_pim_employee_distribution_legend']/table/tbody/tr[2]/td[2]"))
					.getText();
			Assert.assertEquals(linkTwo, options);
			break;

		case "Client Services":
			String linkThree = hooks.getDriver()
					.findElement(
							By.xpath("//*[@id='div_legend_pim_employee_distribution_legend']/table/tbody/tr[3]/td[2]"))
					.getText();
			Assert.assertEquals(linkThree, options);
			break;
		default:
			break;

		}
	}
}

Create a Test Runner Class to execute the tests.

import org.junit.runner.RunWith;

import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;

@RunWith(Cucumber.class)

@CucumberOptions(features= {"src/test/resources"}, glue= {"com.cucumber"})
public class RunCucumberTest {

}

Execute the tests either through JUnit Runner or Command-Line using maven.

The test Report can be accessed from the link provided in the execution status:

We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s