1

My feature file contains a feature that needs to be reused by each and every step definition file again & again. How to manage the code

My feature is :- "User is on home Page".

The above feature / scenario contains a code that needs to be reused again & again. In my code base , for every feature file i have written separate step definition.

My first step definition file :-

@Given ("^user is on  HomePage$")
    public void user_homePage()
    {
        configFileReader =new ConfigFileReader();
        System.setProperty("webdriver.chrome.driver","D:\\chromedriver.exe");
        driver=new ChromeDriver();
        driver.get("https://parabank.parasoft.com/parabank/index.htm");
        driver.manage().window().maximize();
    }

Now the same feature needs to be used in another step definition file. i.e here below

Before user clicks on 'Register' link , it should verify that user is on homePage. The description of 'User is on home page' is defined in first step definition file .

Now how to manage the code here :-

My Second Step definition file here below:-

import StepFiles.ParaBank_TC_01_Step; [ I have even imported first step definition file , so that feature "User is on home page" could be executed. ]

public class ParaBank_TC_02_Step  {

    public  WebDriver driver;
    ConfigFileReader configFileReader;



      @When ("^user clicks on register link$")
        public void click_register() throws InterruptedException
        {

             Thread.sleep(3000);     
             WebElement register_link= driver.findElement(By.xpath("//a[contains(text(),'Register')]"));
             register_link.click();
        }

Actual Result :- 1. When i write all the step definition for 2 features files in one file , then it executes perfectly fine , because feature 'User is on home page' is defined in one same file.

  1. As i write separate step definition for feature 2 in another java file. It shows me "Null pointer exception" error because on feature "User is on home page" > driver is initialised in 1 step def file . It isn't executing for second step definition file.

Please help me out in understanding the root cause of this issue & provide the best possible solution.

  • I have even used "@Before" annotation on step "User is on home page" so that it could be executed before each method . – neha sharma Jul 12 '19 at 07:07
  • You should initialise the driver outside of the steps and then the given step would be just, driver.get(uri) – Stephen K Jul 12 '19 at 07:57

2 Answers2

2

In order to share state between steps, you can use dependency injection (DI). Cucumber offers support for several DI frameworks. We recommend you use either the one your application already uses / you are familiar with (in my case, that is Spring). Otherwise, we recommend PicoContainer as the most lightweight option.

You can find a little more information about using DI in the Cucumber docs and the related code on GitHub.

For more information on using PicoContainer, see this blogpost.

To use Spring, please have a look at my blogpost.

To use Guice, have a look at this blogpost.

Sidenote: Feature-coupled step definitions (defining the step definitions for each feature in a separate file, in a way so that they cannot be reused across features), is considered an anti-pattern, as "This may lead to an explosion of step definitions, code duplication, and high maintenance costs." (from the Cucumber docs).

The solution is to decouple your step definitions: " * Organise your steps by domain concept.

  • Use domain-related names (rather than feature- or scenario-related names) for your step & step definition files." (from the Cucumber docs).

In order to do so, you will need to use DI.

Marit
  • 2,399
  • 18
  • 27
0

If you are interested to implement PicoContainer, please follow below steps for good understanding :

Step 1. OrderSelectionStepDef & OrderDetailsStepDef would look like below (please change name as per your implementation)

/**
 * Step Definition implementation class for Cucumber Steps defined in Feature file
 */

public class HomePageSteps extends BaseSteps {

    TestContext testContext;

    public HomePageSteps(TestContext context) {
        testContext = context;
    }

    @When("^User is on Brand Home Page (.+)$")
    public void user_is_on_Brand_Home_Page(String siteName) throws InterruptedException {
        homePage = new HomePage().launchBrandSite(siteName);
        testContext.scenarioContext.setContext(Context.HOMEPAGE, homePage);
    }

    @Then("^Clicking on Sign In link shall take user to Sign In Page$")
    public void clicking_on_Sign_In_link_shall_take_user_to_Sign_In_Page() {
        homePage = (HomePage) testContext.scenarioContext.getContext(Context.HOMEPAGE);
        signInPage = homePage.ecommSignInPageNavigation();
        testContext.scenarioContext.setContext(Context.SIGNINPAGE, signInPage);
    }

For your reference

public class BaseSteps {

    protected HomePage homePage;
    protected PLPPage plpPage;
    protected PDPPage pdpPage;
    protected ShoppingBagPage shoppingBagPage;
    protected ShippingPage shippingPage;

More implementation goes here.....  

}

Step 2. Please add below 2 Classes under your framework -

First, Java file name - ScenarioContext.java

public class ScenarioContext {

    private  Map<String, Object> scenarioContext;

    public ScenarioContext(){
        scenarioContext = new HashMap<String, Object>();
    }

    public void setContext(Context key, Object value) {
        scenarioContext.put(key.toString(), value);
    }

    public Object getContext(Context key){
        return scenarioContext.get(key.toString());
    }

    public Boolean isContains(Context key){
        return scenarioContext.containsKey(key.toString());
    }
}

Second, Java file name - TestContext.java

public class TestContext {

    public ScenarioContext scenarioContext;

    public TestContext(){
        scenarioContext = new ScenarioContext();
    }

    public ScenarioContext getScenarioContext() {
        return scenarioContext;
    }
}

Step 3. POM Dependency - picocontainer shall be as per your cucumber version

   <dependency>
        <groupId>io.cucumber</groupId>
        <artifactId>cucumber-picocontainer</artifactId>
        <version>${cucumber.version}</version>
    </dependency>
TheSociety
  • 1,936
  • 2
  • 8
  • 20