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:
Run the same set of tests but with different parameter value.
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();
}