Cucumber: Sharing Test Context between Step Definitions using PicoContainer

Profile picture for user arilio666

In cucumber, when it comes to sharing between multiple-step definition files, dependency injection is one of the option to be used.

  • We can share test context to other step definitions using a dependency called pico container in cucumber through dependency injection.
  • There are other options as well such as cucumber-picocontainer, cucumber-guice, cucumber-openejb, cucumber-spring, cucumber-weld and cucumber-needle also for dependency injection.
  • But today, in this article, we will be covering dependency injection via constructor injection orchestrated by pico container.

Step 1: Add PicoContainer dependency to POM

So dependency while writing this article is this, you can download the latest one from here:

<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-picocontainer</artifactId>
    <version>7.2.1</version>
</dependency>

Step 2: Create or Update Base class 

Okay, let us see how we can share test context between step definitions step by step. We will be using a simple integer variables passing between two steps using the base class.

Okay, first, let us create a base class.

public class Base
{
    public int num1;
    public int num2;
}

Here we have created a base class with the two integer variable num1 and num2.

Step 3: Create a feature file

@testnumber
Scenario: Test 1
Then I set numbers  
Then I read number one
And I read number two 

Step 4: Constructor Injection in First Step Definition File

2 steps that we are gonna follow while doing the constructor injection is:

  1. To create a reference variable in the current step class.
  2. To initialize the reference variable via the constructor.

So let us take a look at our step definition class.

public class FirstStepDef
{
    private Base base;
	
    public FirstStepDef(Base base)
    {
        this.base = base;
    }
	
    @Then("I set numbers")
    public void i_increment_number()
    {
        base.num1 = 10;
        base.num2 = 20;
    }
}
  • In above step we are assigning value 10 and 20 to num1 and num2 respectively, which was created in Base class.
  • Picocontainer will automatically create the object and provide the variable value to the post-step definition.
  • So, in constructor injection, after we create an object of the base class, which is automatically done by the pico container, we will be providing the step definition class of the base class using the constructor.
  • So firstly, we have created a private variable of Base.
  • Now we will create the constructor of the step class and pass the reference variable we created 'base' inside the constructor.
  • We will initialize the local variable inside the constructor using 'this.'

Now all is done.

  • During the runtime, the pico container will automatically create the base class Base and inject it into the FirstStepDef step definition class via constructor.
  • So the object which will get created will be supplied to the FirstStepDef class and Base inside the constructor.

Step 5: Access the variable in another step definition file

Now let us access the modified variable in another step class

public class SecondStepDef
{
    private Base base;
	
    public SecondStepDef(Base base)
    {
        this.base = base;
    }
	
    @Then("I read number one")
    public void i_print_number_one()
    {
        System.out.println(base.num1); 
    }
	
    @Then("I read number two")
    public void i_print_number_two()
    {
        System.out.println(base.num2); 
    }
}
  • We have used the base variable we initialized here and fetched the num1 and num2 variable from base.
  • Note that if private Base base; is not initialized here, it will throw a null pointer exception.

Output

10
20

Now we can pretty much handle all the web driver context passing and other base class usage via this injection method, thanks to pico container for seamless data sharing.