Dependency Injection Using PicoContainer in Cucumber

In the Cucumber framework, we often need to share state between steps to verify data or reuse objects like WebDriver, user info, or test results.

If all the step definitions are written in the same class, sharing state is straightforward. But putting all step logic into a single class becomes hard to maintain and scale, especially as the project grows.

However, if the step definitions are placed across multiple classes (which is the clean and modular way), sharing state directly between them is not possible by default.

PicoContainer

To overcome this, we can use PicoContainer, a lightweight Dependency Injection (DI) library. It allows us to share context or data between different step definition classes using constructor injection.

There are other DI libraries like Spring, Guice, Weld, OpenEJB, and Needle, but in this tutorial, we’ll use PicoContainer, as it is natively supported by Cucumber.

Add PicoContainer Dependency

Search for pico container dependency, copy the code and paste it in pom.xml

<!-- https://mvnrepository.com/artifact/io.cucumber/cucumber-picocontainer -->
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>7.23.0</version>
</dependency>


Use Case: Sharing Username Between Steps

Let's say we have this scenario:

Scenario: Verify user deposit the amount and generate the report
  Given user navigate the url in the browser
  When user select the manager login
  And add the customer with "username", "lastname", "postcode"
  And existing customer loggedIn
  And download the report


Assume:

     The first 4 steps are defined in DepositStepDefinitions.java
     The last step is defined in ReportStepDefinitions.java

We want to share the username between them.

Step 1: Create a Shared Data Class

// test/utils/DataClass.java
package test.utils;
public class DataClass {
    private String username;
    public void setUserName(String username) {
        this.username = username;
    }
    public String getUserName() {
        return username;
    }
}

 

Step 2: Inject into Deposit Step Definition

// StepDefinitions/DepositStepDefinitions.java
package StepDefinitions;
import io.cucumber.java.en.*;
import test.utils.DataClass;
public class DepositStepDefinitions {
    DataClass data;
    // Constructor injection by PicoContainer
    public DepositStepDefinitions(DataClass data) {
        this.data = data;
    }
    @Given("user navigate the url in the browser")
    public void userNavigateTheUrlInTheBrowser() {
        System.out.println("User navigates to the URL...");
    }
    @When("user select the manager login")
    public void userSelectTheManagerLogin() {
        System.out.println("Manager login selected.");
    }
    @And("add the customer with {string}, {string}, {string}")
    public void addTheCustomerWith(String username, String lastname, String postcode) {
        data.setUserName(username);
        System.out.println("Customer added - Username: " + username);
    }
    @And("existing customer loggedIn")
    public void existingCustomerLoggedIn() {
        System.out.println("Customer logged in: " + data.getUserName());
    }
}


Step 3: Inject into Report Step Definition

// StepDefinitions/ReportStepDefinitions.java
package StepDefinitions;
import io.cucumber.java.en.And;
import test.utils.DataClass;
public class ReportStepDefinitions {
    DataClass data;
    public ReportStepDefinitions(DataClass data) {
        this.data = data;
    }
    @And("download the report")
    public void downloadTheReport() {
        System.out.println("Generating report for user: " + data.getUserName());
    }
}


Output

User navigates to the URL...
Manager login selected.
Customer added - Username: Erick
Customer logged in: Erick
Generating report for user: Erick

 

Related Tutorials