0

I want to get WebDriver Instance(Object) from the Hooks Class in @Before Annotation setup() method. And I want to do it in such a way that I am able to run my scenarios in parallel.

I know what are Hooks and @Before annotation in cucumber but I am not able to understand how do I start my browser and pass that instance to the step definition class.

I have created a sample project to highlight the issue. I have a feature file with 2 scenarios. Those two scenario are go to Bing and Google search pages and verifying the page titles respectively.

Below is my Sample code and project structure:

Project structure:

enter image description here

PageTitleVerification.feature

Feature: Verify the title of the search pages

  @regression
  Scenario: Validate the Bing Home Page title
    Given Go to Bing Home Page
    Then  Verify Bing page title
    
    
  @regression
  Scenario: Validate the Google Home Page title
    Given Go to Google Home Page
    Then  Verify Google page title

BingHomePage.java

public class BingHomePage {
    WebDriver driver;
    
    public BingHomePage(WebDriver driver) {
        this.driver = driver;
        PageFactory.initElements(driver, this);
    }
    
    public void gotoBingHomePage() {
        driver.navigate().to("https://www.bing.com/");
    }
    
    public boolean verifyBingPageTitle() {
        String expectedPageTitle = "Bing";
        String actualPageTitle = driver.getTitle();
        
        return actualPageTitle.equals(expectedPageTitle);
    }
    
}

GoogleHomePage.java

public class GoogleHomePage {

    WebDriver driver;

    public GoogleHomePage(WebDriver driver) {
        this.driver = driver;
        PageFactory.initElements(driver, this);
    }

    public void gotoGoogleHomePage() {
        driver.navigate().to("https://www.google.com/");
    }

    public boolean verifyGooglePageTitle() {
        String expectedPageTitle = "Google";
        String actualPageTitle = driver.getTitle();
        
        return actualPageTitle.equals(expectedPageTitle);
    }

}

BingStepDef.java

public class BingStepDef implements En {

    //Question: 
    //How do I initialize this driver instance with the Hooks @Before
    WebDriver driver ;

    BingHomePage bingHomePage;

    public BingStepDef() {

        bingHomePage = new BingHomePage(driver);
        
        Given("Go to Bing Home Page", () -> {
            bingHomePage.gotoBingHomePage();
        });

        Then("Verify Bing page title", () -> {
            boolean result = bingHomePage.verifyBingPageTitle();
            Assert.assertTrue(result);
        });

    }

}

GoogleStepDef.java

public class GoogleStepDef implements En {

    //Question: 
    //How do I initialize this driver instance with the Hooks @Before
    WebDriver driver ;
    
    GoogleHomePage googleHomePage;
    
    public GoogleStepDef() {
        
        googleHomePage = new GoogleHomePage(driver);

        Given("Go to Google Home Page", () -> {
            googleHomePage.gotoGoogleHomePage();
        });

        Then("Verify Google page title", () -> {
            boolean result = googleHomePage.verifyGooglePageTitle();
            Assert.assertTrue(result);
        });
    
    }

}

Hooks.java

public class Hooks {

    WebDriver driver;
    
    @Before
    public void setup() {
        System.setProperty("webdriver.chrome.driver", "./src/main/resources/Drivers/chromedriver.exe");
        driver = new ChromeDriver();
    }
    
    @After
    public void tearDown() {
        driver.quit();
    }
    
}

TestRunner.java

@RunWith(Cucumber.class)
@CucumberOptions(
        features = "src/main/java/com/alok/feature/"
        , glue = {"com.alok.stepdef"}
        , plugin = {"pretty","html:target/cucumber"}
        , dryRun = false
        , monochrome = true
        , tags = {"@regression"}
)
public class TestRunner {
    
}

TestRunnerParallel.java

@RunWith(Cucumber.class)
@CucumberOptions(
        features = "./src/main/java/com/alok/feature"
        , glue = {"com.alok.stepdef"}
        , plugin = {"pretty","html:target/cucumber"}
        , dryRun = false
        , monochrome = true
        , tags = {"@regression"}
)

public class TestRunnerParallel extends AbstractTestNGCucumberTests {

    @Override
    @DataProvider(parallel = true) 
    public Object[][] scenarios() {
        return super.scenarios();
    }

}

TestNG.XML

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite" data-provider-thread-count="2">
    <test name="Test Regression" >
         <classes>
             <class name="com.alok.test.TestRunnerParallel"/>
          </classes>
     </test> 
</suite>
  • Sorry for opptopic. Why are you using PageFactory.init? You do not have fields in your page objects except of a driver field. So there is nothing to initialize in your objects. – Alexey R. Jul 2 at 7:51
  • You are correct,Alexey. This just a sample project I created to put my question across. kindly ignore PageFactory.init. Thanks. – Alok Jul 2 at 7:57
  • Have you tried to run your current configuration in parallel? As far as I can see you create a new instance of webdriver in @Before. Shouldn't that be enough? – Alexey R. Jul 2 at 11:09
  • No, Alexey. I am not able to pass that instance to the StepDef Classes viz: BingStepDef , GoogleStepDef – Alok Jul 2 at 11:16
2

You shouldn't use hooks to supply WebDriver to your scenarios. Instead use PicoContainer dependency injection framework.

  1. Mark the fields of your step class with @Inject annotations
  2. Create a class that would implement WebDriver interface and delegate calls to internal driver object that would be lazily initialized. That class should also implement Disposable interface where you kill your internal driver object.
  3. Create custom object factory that would delegate calls to PicoFactory. In the constructor of your custom factory add classes that should be injected according to your steps logic
  4. Register your factory as SPI service.
  5. Set cucumber.object-factory property in cucumber.properties file pointing to your custom factory

This should be enough. Here is more detailed tutorial of making your cucmber-java8 work with PicoContainer.

| improve this answer | |
  • Thanks Alexey. The solutions that have provided in the links are using Cucumber prior to the Lambda expressions. I am using Cuccumber-Java8(as mentioned in question) its not working for it. – Alok Jul 2 at 14:42
  • I believe they have to work in your cucumber as well. It is just a concept that does not rely on Java version. – Alexey R. Jul 2 at 14:51
  • I meant Alexey was that in new Cucumber Step Def class we have to implement En interface (io.cucumber.java8.En) i.e public class GoogleStepDef implements En { and we define the steps inside a constructor (with no arguments) unlike earlier we used the @Given annotation. public GoogleStepDef() { and Given("Go to Google Home Page", () -> { //.... }); Refer the GoogleStepDef class shown in the question. Since Pico forces us to define a constructor with arguments and in the new Cucumber Step Def we have to define the constructor without argument this is where I am getting stuck. – Alok Jul 3 at 10:04
  • Updated the answer – Alexey R. Jul 7 at 19:18
  • Thanks Alexey. Will try it and let you know. might take a couple of days to revert. :-) – Alok Jul 8 at 5:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.