Passing data between steps in Cucumber

Posted on

When writing test automation using Cucumber, you often need to pass data from one step to another. Cucumber doesn't store data between steps automatically, but you can achieve this using instance variables, dependency injection and Scenario Context.

Approach 1: Using Instance Variables

The easiest way to share data between steps is by using instance variables inside a step definition class.

Java
Copy
public class LoginSteps {
    private String username;

    @Given("User enters username {string}")
    public void userEntersUsername(String username) {
        this.username = username;  // Store data in instance variable
    }

    @When("User logs in")
    public void userLogsIn() {
        System.out.println("Logging in with username: " + username);
    }

    @Then("User should see their profile")
    public void userShouldSeeProfile() {
        System.out.println("Verifying profile for user: " + username);
    }
}

Approach 2: Using Scenario Context


Step 1: Create Scenario Context Class

Java
Copy
import java.util.HashMap;
import java.util.Map;

public class ScenarioContext {
    private Map<String, Object> data = new HashMap<>();

    public void setData(String key, Object value) {
        data.put(key, value);
    }

    public Object getData(String key) {
        return data.get(key);
    }
}

Step 2: Use Scenario Context in Step Definitions

Java
Copy
public class LoginSteps {
    private ScenarioContext scenarioContext;

    // Constructor-based Dependency Injection
    public LoginSteps(ScenarioContext scenarioContext) {
        this.scenarioContext = scenarioContext;
    }

    @Given("User enters username {string}")
    public void userEntersUsername(String username) {
        scenarioContext.setData("username", username);
    }

    @When("User logs in")
    public void userLogsIn() {
        String username = (String) scenarioContext.getData("username");
        System.out.println("Logging in with username: " + username);
    }

    @Then("User should see their profile")
    public void userShouldSeeProfile() {
        String username = (String) scenarioContext.getData("username");
        System.out.println("Verifying profile for user: " + username);
    }
}

Approach 3: Using Dependency Injection with PicoContainer


If you use PicoContainer, you don’t need to manually create ScenarioContext. Instead, Cucumber automatically injects dependencies.

Step 1: Define a Shared Class

Java
Copy
public class SharedData {
    private String username;

    public void setUsername(String username) {
        this.username = username;
    }

    public String getUsername() {
        return username;
    }
}

Step 2: Inject SharedData into Step Definitions

Java
Copy
public class LoginSteps {
    private final SharedData sharedData;

    // PicoContainer automatically injects this
    public LoginSteps(SharedData sharedData) {
        this.sharedData = sharedData;
    }

    @Given("User enters username {string}")
    public void userEntersUsername(String username) {
        sharedData.setUsername(username);
    }

    @When("User logs in")
    public void userLogsIn() {
        System.out.println("Logging in with username: " + sharedData.getUsername());
    }

    @Then("User should see their profile")
    public void userShouldSeeProfile() {
        System.out.println("Verifying profile for user: " + sharedData.getUsername());
    }
}