Home > Enterprise >  Can a TestNG cross-browser test be executed with Cucumber runner?
Can a TestNG cross-browser test be executed with Cucumber runner?

Time:02-13

I am working with Selenium Webdriver with Cucumber. My tests work as expected with that combination. In order to achieve cross-browser testing, I added TestNG framework. To verify that my cross-browser test was working good, I ran it with TestNG alone, without Cucumber. It ran perfectly in both Chrome and Firefox browsers.

public class WebTest {


  WebDriver driver = null;
  BasePageWeb basePage;
  public String browser;


  @Parameters({ "Browser" })
  public WebTest(String browser) {
    this.browser = browser;
  }

  
  @BeforeClass
  public void navigateToUrl() {
    switch (browser) {

      case "CHROME":
        WebDriverManager.chromedriver().setup();
        driver = new ChromeDriver();
        break;

      case "FF":
        WebDriverManager.firefoxdriver().setup();
        driver = new FirefoxDriver();
        break;

      default:
        driver = null;
        break;
    }
    driver.get("https://demosite.executeautomation.com/Login.html");

  }

  @Test
  public void loginToWebApp() {

    basePage = new BasePageWeb(driver);
    basePage.enterUsername("admin")
            .enterPassword("admin")
            .clickLoginButton();

    driver.quit();
  }

}

The testng.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">

<suite name="Suite" parallel="tests" thread-count="5">

    <test name="Chrome Test">
        <parameter name="Browser" value="CHROME"/>
        <classes>
            <class name="tests.web.WebTest"/>
        </classes>
    </test>
    <test name="Firefox Test">
        <parameter name="Browser" value="FF"/>
        <classes>
            <class name="tests.web.WebTest"/>
        </classes>
    </test>
</suite>

I needed to integrate the TestNG test with my Cucumber set-up so that I can run the whole test with Cucumber. To do this, I added cucumber-testng dependency to POM and created a Cucumber runner extending the AbstractCucumberTestNG class. I specified the location of my feature file and step definition. The step definition is mapped to the TestNG test.

Cucumber runner:

@CucumberOptions(
                plugin = {"pretty", "html:target/surefire-reports/cucumber",
                        "json:target/surefire-reports/cucumberOriginal.json"},
                glue = {"stepdefinitions"},
                tags = "@web-1",
                features = {"src/test/resources/features/web.feature"})
          
   

 public class RunCucumberNGTest extends AbstractTestNGCucumberTests {
    }

Step definition:

public class WebAppStepDefinitions {
      private final WebTest webTest = new WebTest("CHROME"); //create an object of the class holding the testng test. If I change the argument to FF, the test will run only on Firefox
      static boolean prevScenarioFailed = false;
    
    
      @Before
      public void setUp() {
        if (prevScenarioFailed) {
          throw new IllegalStateException("Previous scenario failed!");
        }
    
      }
    
      @After()
      public void stopExecutionAfterFailure(Scenario scenario) throws Exception {
        prevScenarioFailed = scenario.isFailed();
      }
    
      @Given("^I have navigated to the web url \"([^\"]*)\"$")
      public void navigateToUrl(String url) {  test
        webTest.navigateToUrl(url); //calling the first method holding the testng
      }
    
    
      @When("^I log into my web account with valid credentials as specicified in (.*) and (.*)$")
      public void logintoWebApp(String username, String password) {
        webTest.loginToWebApp(username, password); //calling the second method holding the testng
      }
    }

On running the class, the test got executed only in one browser (Chrome). Somehow, Firefox got lost in the build-up. I suspect that I am calling the parameterised TestNG method wrongly from another class. How do I do the call successfully?

CodePudding user response:

For running TestNG tests with Cucumber you have to define Test Runner classes in testng.xml.

your Test Runner class is RunCucumberNGTest.

So the xml should look like:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">

<suite name="Suite" parallel="tests" thread-count="5">

    <test name="Chrome Test">
        <parameter name="Browser" value="CHROME"/>
        <classes>
            <class name="some.package.name.RunCucumberNGTest"/>
        </classes>
    </test>
    <test name="Firefox Test">
        <parameter name="Browser" value="FF"/>
        <classes>
            <class name="some.package.name.RunCucumberNGTest"/>
        </classes>
    </test>
</suite>

From this xml I see the next requirements:

  1. Run the same set of tests but with different parameter value.

  2. This should work in parallel, so this should be thread-safe.


1 Introduce TestNG Parameter for Test Runner class

@CucumberOptions(
                plugin = {"pretty", "html:target/surefire-reports/cucumber",
                        "json:target/surefire-reports/cucumberOriginal.json"},
                glue = {"stepdefinitions"},
                tags = "@web-1",
                features = {"src/test/resources/features/web.feature"})
public class RunCucumberNGTest extends AbstractTestNGCucumberTests {

    // static thread-safe container to keep the browser value
    public final static ThreadLocal<String> BROWSER = new ThreadLocal<>();

    @BeforeTest
    @Parameters({"Browser"})
    public void defineBrowser(String browser) {
        //put browser value to thread-safe container
        RunCucumberNGTest.BROWSER.set(browser);
        System.out.println(browser);
    }

}

2 Use the value in Step Definition class

public class WebAppStepDefinitions {
      private WebTest webTest;
      static boolean prevScenarioFailed = false;
    
      @Before
      public void setUp() {
        if (prevScenarioFailed) {
          throw new IllegalStateException("Previous scenario failed!");
        }
        //get the browser value for current thread
        String browser = RunCucumberNGTest.BROWSER.get();
        System.out.println("WebAppStepDefinitions: "   browser);
        //create an object of the class holding the testng test. If I change the argument to FF, the test will run only on Firefox
        webTest = new WebTest(browser);
      }
    
      @After
      public void stopExecutionAfterFailure(Scenario scenario) throws Exception {
        prevScenarioFailed = scenario.isFailed();
      }
    
      @Given("^I have navigated to the web url \"([^\"]*)\"$")
      public void navigateToUrl(String url) {
        webTest.navigateToUrl(url); //calling the first method holding the testng
      }
    
    
      @When("^I log into my web account with valid credentials as specicified in (.*) and (.*)$")
      public void logintoWebApp(String username, String password) {
        webTest.loginToWebApp(username, password); //calling the second method holding the testng
      }

}

NOTE: All TestNG annotations should be removed from WebTest class, they won't work and not required. WebTest used explicitly by WebAppStepDefinitions class, all the methods invoked explicitly and not by TestNG.

So, based on your initial requirements:

public class WebTest {

  WebDriver driver = null;
  BasePageWeb basePage;
  public String browser;

  public WebTest(String browser) {
    this.browser = browser;
  }

  public void navigateToUrl(String url) {
    switch (browser) {

      case "CHROME":
        WebDriverManager.chromedriver().setup();
        driver = new ChromeDriver();
        break;

      case "FF":
        WebDriverManager.firefoxdriver().setup();
        driver = new FirefoxDriver();
        break;

      default:
        driver = null;
        break;
    }
    driver.get(url);

  }

  public void loginToWebApp(String username, String password) {

    basePage = new BasePageWeb(driver);
    basePage.enterUsername(username)
            .enterPassword(password)
            .clickLoginButton();

    driver.quit();
  }
  • Related