Parameterized Selenium Tests in Parallel with TestNG - java

First of all, sorry for my english, it's not so perfect :)
So I'm facing with the following problem: I'm trying to run parallel tests in different browsers using Selenium Grid and TestNg and I pass the parameters in the #BeforeTest method. My problem is that when every test get initialized, it seems that they will use the last test's parameters. So in this example when I run the test, it will open two Chrome, instead of one Firefox and one Chrome.
(The browser.getDriver() method returns a RemoteWebDriver)
TestNG.xml:
<suite thread-count="2" verbose="10" name="testSuite" parallel="tests">
<test name="nameOfTheTestFirefox">
<parameter name="platform" value="windows"/>
<parameter name="browserVersion" value="32"/>
<parameter name="browserName" value="firefox"/>
<classes>
<class name="example.test.login.LoginOverlayTest"/>
</classes>
</test> <!-- nameOfTheTestFirefox -->
<test name="nameOfTheTestChrome">
<parameter name="platform" value="windows"/>
<parameter name="browserVersion" value="38"/>
<parameter name="browserName" value="chrome"/>
<classes>
<class name="example.test.login.LoginOverlayTest"/>
</classes>
</test> <!-- nameOfTheTestChrome -->
</suite> <!-- testSuite -->
The AbstractTest class:
public class SeleniumTest {
private static List<WebDriver> webDriverPool = Collections.synchronizedList(new ArrayList<WebDriver>());
private static ThreadLocal<WebDriver> driverThread;
public static BrowserSetup browser;
#Parameters({ "browserName", "browserVersion", "platform"})
#BeforeTest()
public static void beforeTest(String browserName, #Optional("none") String browserVersion, String platform) throws WrongBrowserException, WrongPlatformException {
final BrowserSetup browser = new BrowserSetup(browserName, browserVersion, platform);
driverThread = new ThreadLocal<WebDriver>() {
#Override
protected WebDriver initialValue() {
final WebDriver webDriver = browser.getDriver();
webDriverPool.add(webDriver);
return webDriver;
}
};
}
public static WebDriver getDriver() {
return driverThread.get();
}
#AfterTest
public static void afterTest() {
for (WebDriver driver : webDriverPool) {
driver.quit();
}
}
}
And my example #Tests:
#Test
public void test1() throws InterruptedException {
WebDriver driver = getDriver();
System.out.println("START: test1");
driver.get("http://google.com");
Thread.sleep(5000);
System.out.println("END: test1, title: " + driver.getTitle());
}
#Test
public void test2() throws InterruptedException {
WebDriver driver = getDriver();
System.out.println("START: test2");
driver.get("http://amazon.com");
Thread.sleep(5000);
System.out.println("END: test2, title: " + driver.getTitle());
}
#Test
public void test3() throws InterruptedException {
WebDriver driver = getDriver();
System.out.println("START: test3");
driver.get("http://stackoverflow.com");
Thread.sleep(5000);
System.out.println("END: test3, title: " + driver.getTitle());
}
So my question is how can I run the tests in parallel with the given parameters in separate threads?
Thanks in advance!
Peter

Don't make the fields static.
private static List<WebDriver> webDriverPool = Collections.synchronizedList(new ArrayList<WebDriver>());
private static ThreadLocal<WebDriver> driverThread;
public static BrowserSetup browser;

beforeTest() and afterTest() shouldn't be static if you want to run it in parallel, or make it synchronized to have it thread safe. Also, you do not use declared variable:
public static BrowserSetup browser;
at all, or you missed something there since you also have:
final BrowserSetup browser = new BrowserSetup(browserName, browserVersion, platform);
inside beforeTest(...)

Related

Java + Selenium Session ID is null. Using WebDriver after calling quit()

I am having issues trying to run Selenium Web driver in a specific way, I've have setup TestNG + Selenium Web driver in my framework, the thing that I would like to accomplish is to run two suites that I've set up in the TestNG.xml files as bellow:
TestNG.xml
<suite>
<suite-files>
<suite-file path="src/testNG/suites/UserSignsOn.xml" />
<suite-file path="src/testNG/suites/PreSetup.xml" />
</suite-files>
</suite>
PreSetup.xml
<suite name="Pre Setup">
<test name="pre setup suite">
<classes>
<class name="Tests.PreSetup" />
</classes>
</test>
</suite>
UserSignsOn.xml
<suite name="User Signs On">
<test name="Get the Web Application">
<classes>
<class name="Tests.LoginPageTest" />
</classes>
</test>
</suite>
My test files look like this:
LoginPageTest.class
public class LoginPageTest extends BaseTest {
#Test
#Description("Login to the web application")
public void signInTheWebApplicationLocalHost(){ // some steps here }
}
PreSetup.class
public class PreSetup extends BaseTest {
#Test
#Description("Pre setup")
public void preSetupSteps(){ // some steps here }
}
As you can see my Test files extends a class, which is the following:
BaseTest.class
public class BaseTest {
protected EnvironmentManager environmentManager;
#BeforeTest
public void testSetup() {
environmentManager = EnvironmentManager.getInstance();
if(environmentManager.getDriver() == null){
// Here I am set up the driver!!!
environmentManager.initWebdriver();
environmentManager.startWebApplication();
}
}
#BeforeMethod
public void testName(ITestResult result){ // perform some actions }
#AfterMethod
public void status(ITestResult result){ // perform some actions }
#AfterTest // Here I am shutting down the driver
public void tearDown() { environmentManager.shutdownDriver(); }
}
The BaseTest.class calls to the EnvironmentManager.class which is a singleton class
It has the bellow code:
public class EnvironmentManager {
private static EnvironmentManager instance = null;
private WebDriver driver = null;
private String url = "www.google.com";
private EnvironmentManager(){}
// Public Methods
public void initWebdriver() {
if(driver == null){ driver = new ChromeDriver(); }
}
public void startWebApplication(){ driver.get(url); }
// Singleton method
public static EnvironmentManager getInstance() {
if (instance == null) instance = new EnvironmentManager();
return instance;
}
public void shutdownDriver(){
driver.quit();
driver = null;
}
public WebDriver getDriver(){ return driver; }
}
The issue resides after running the second test "PreSetup", in the console I got the error:
Session ID is null. Using WebDriver after calling quit()?
I notice that in the first test the driver session is:
ChromeDriver: chrome on MAC (0ff799fbfd14fc275b3b45c414765b15)
And in the second test is a different one:
ChromeDriver: chrome on MAC (09c6c47344756fe2979ee8a84094b1e3)
Any help is welcome :)
for all interested the solution is to rename the following testNG annotations:
#BeforeTest
#AfterTest
to
#BeforeSuite
#AfterSuite

How to use the same browser window in multiple classes using TestNG Selenium webdriver in java?

I am trying to automate a webpage which has a login and post login has many menu item. I would like to automate it in such a way that it logs into the webpage only once and then use the different menu items. Each new menu item automation is created in a different class.
package pack1;
public class Init {
public WebDriver driver;
ChromeOptions options;
#BeforeSuite
public void beforeSuite() throws AWTException, InterruptedException, IOException {
//Setting Chrome Driver and disabling the save password option
System.setProperty(“webdriver.chrome.driver”,”C:\\Users\\user\\Desktop\\Demo\\chromedriver.exe”);
options = new ChromeOptions();
Map<String, Object> prefs = new HashMap<String, Object>();
prefs.put(“credentials_enable_service”, false);
prefs.put(“profile.password_manager_enabled”, false);
options.setExperimentalOption(“prefs”, prefs);
driver=new ChromeDriver(options);
//Opening the URL
driver.get(“myURL”);
driver.manage().window().maximize();
//Login to the portal
driver.findElement(By.xpath(“.//*[#id=’content-wrapper’]/div/div/div/div/div/div/div/form/div/div[1]/input”)).sendKeys(username);
driver.findElement(By.xpath(“.//*[#id=’content-wrapper’]/div/div/div/div/div/div/div/form/div/div[2]/input”)).sendKeys(password);
driver.findElement(By.xpath(“.//*[#id=’content-wrapper’]/div/div/div/div/div/div/div/form/div/div[3]/button”)).click();
}
#AfterSuite
public void afterSuite() {
//Closing the driver
// driver.close();
}
}
Class A
package pack1;
public class ClassA extends Init{
#Test (priority=0, enabled = true)
public void Setup() throws InterruptedException{
//Traversing the menu to reach contract grower setup
Thread.sleep(5000);
driver.findElement(By.linkText(“Menu1”)).click();
driver.findElement(By.linkText(“SubMenu1”)).click();
}
}
Class B
package pack1;
public class ClassBextends Init{
#Test (priority=0, enabled = true)
public void Setup() throws InterruptedException{
//Traversing the menu to reach contract grower setup
Thread.sleep(5000);
driver.findElement(By.linkText(“Menu2”)).click();
driver.findElement(By.linkText(“SubMenu2”)).click();
}
}
testing.xml
<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE suite SYSTEM “http://testng.org/testng-1.0.dtd”>
<suite name=”Suite”>
<test name=”Test”>
<classes>
<class name=”pack1.ClassA”/>
<class name=”pack1.ClassB”/>
<class name=”pack1.Init”/>
</classes>
</test> <!– Test –>
</suite> <!– Suite –>
You should make the following changes:
Configure WebDriver in the Init Class to be static
Don't inherit the Init class in the Test Classes
To use driver in test classes, access it as Init.getDriver();
Base Class
public class Init {
private static WebDriver driver;
public static WebDriver getDriver() {
return driver;
}
#BeforeSuite
public void beforeSuite() {
System.out.println("BS");
System.setProperty("webdriver.chrome.driver", "");
driver = new ChromeDriver();
driver.get("https://www.google.com");
}
#AfterSuite
public void afterSuite() {
System.out.println("AS");
driver.quit();
}
}
Class A
public class ClassA {
#Test(priority = 0, enabled = true)
public void classATest() throws InterruptedException {
System.out.println("classATest");
Init.getDriver().findElement(By.name("q")).sendKeys("Class 1");
}
}
Class B
public class ClassB {
#Test(priority = 0, enabled = true)
public void class2Test() throws InterruptedException {
System.out.println("classBTest");
Init.getDriver().findElement(By.name("q")).sendKeys("Class 2");
}
}
TestNG XML File
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="System Testing" parallel="none" thread-count="1">
<test name="MenuTest" verbose="0">
<classes>
<class name="com.pack1.ClassA" />
<class name="com.pack1.ClassB" />
<class name="com.pack1.Init" />
</classes>
</test>
</suite>
Output
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running TestSuite
BS
Starting ChromeDriver 2.33.506120 (e3e53437346286c0bc2d2dc9aa4915ba81d9023f) on port 16311
Only local connections are allowed.
Mar 09, 2018 2:33:59 PM org.openqa.selenium.remote.ProtocolHandshake.createSession
INFO: Detected dialect: OSS
classATest
classBTest
AS
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.541 sec - in TestSuite

Test framework architecture using Selenium WebDriver and TestNG

guys. I trying to solve a problem with parallel running using RC Webdriver and TestNG, but unfortunately, I can't find solution last few hours. Maby you will see the code, and show me what, I actually doing wrong.
Goal:
Create architecture using RC WebDriver and TestNG, with an ability to run tests on a remote machine.
Main settings class is Sut:
private RemoteWebDriver driver = null;
#BeforeClass
public WebDriver getWebDriver() {
DesiredCapabilities dc = new DesiredCapabilities();
FirefoxProfile fp = new FirefoxProfile();
dc.setCapability(FirefoxDriver.PROFILE, fp);
dc.setBrowserName(DesiredCapabilities.firefox().getBrowserName());
try {
driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), dc);
} catch (MalformedURLException e) {
e.printStackTrace();
}
return driver;
}
#AfterClass
public void tearDown() {
driver.quit();
}
In this class we have two methods: getWebDriver() - for setup our remote webdriver, and tearDown() - for close web-page, when a test will be complete.
Class BaseStep:
private static ThreadLocal<Sut> sut = new ThreadLocal<Sut>();
public static Sut getSut() {
Sut currentSut = sut.get();
if (currentSut == null) {
currentSut = new Sut();
}
return currentSut;
}
It's an additional layer, which create 'new state for each new thread'.
Few page objects:
public class FacebookPage {
public void testLink() {
getSut().getWebDriver().get("http://facebook.com");
}
}
public class GooglePage {
public void testLink() {
getSut().getWebDriver().get("http://google.com");
}
}
And scenarious classes:
public class VerifyGooglePage {
GooglePage googlePage = new GooglePage();
#Test
public void verifyGoogleMainPage() {
googlePage.testLink();
}
}
public class VerifyFacebookPage {
Facebook facebookPage = new Facebook();
#Test
public void verifyFacebookeMainPage() {
facebookPage.testLink();
}
}
And my and testNG.xml file for running
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite thread-count="1" name="Suite" parallel="tests">
<test name="FirstTest">
<classes>
<class name="scenarious.VerifyGooglePage"/>
</classes>
</test> <!-- Test -->
<test name="SecondTest">
<classes>
<class name="scenarious.VerifyFacebookPage"/>
</classes>
</test> <!-- Test -->
</suite> <!-- Suite -->
The problems is: When test complete, browser is not closed.
the Picture
I watched a lot of tutorials and articles in internet about it, but in no-one I cant found solution for my case. Could you please help me to find what I doing wrong.

Execute one method in one test tag in parallel in testng

This is my class containing test method which I want to execute in parallel.
Each input from Data Provider is a new thread.
When I execute this method in 2 threads as Data Provider has 2 inputs, test hangs in one browser and other executes
public class DemoTest {
private static final ThreadLocal<WebDriver> webDriverThreadLocal= new InheritableThreadLocal<>();
private String baseUrl;
private String severity;
#BeforeMethod
public void beforeMethod() {
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
driver.manage().window().maximize();
webDriverThreadLocal.set(driver);
System.out.println("In before method:"+Thread.currentThread().getId());
System.out.println("FF hashcode:"+driver.hashCode());
}
#DataProvider(name = "data-provider", parallel=true)
public Object[][] dataProviderMethod() throws IOException {
System.out.println("On dp");
new Object[] { 1, "a" },
new Object[] { 2, "b" },
}
public void testProgramOptions(Integer n, String s) {
WebDriver driver = webDriverThreadLocal.get();
baseUrl = "http://www.google.com/";
driver.get(baseUrl);
System.out.println("method f id:"+Thread.currentThread().getId()+" n:"+n+" s:"+s);
//test continues
}
#AfterMethod
public void afterMethod() {
WebDriver driver = webDriverThreadLocal.get();
System.out.println("In after method for id:"+Thread.currentThread().getId());
driver.quit();
}
}
This is testng.xml
<suite name="Suite" parallel="methods">
<test name="prelogin" >
<classes>
<class name="DemoTest"></class>
</classes>
</test>
</suite>

testNG parallel execution not working

I am trying to run following test in parallel for two browsers using testNG, while running both the browsers are getting launched with the URL, but the complete test execution is happening for only one browser.
Here is my Test Suite class
#Test (groups = {"Enable"})
#SuppressWarnings("unused")
public class EETestSuite_01 extends ApplicationFunctions{
String URL = Globals.GC_EMPTY;
#BeforeTest
#Parameters("browser")
public void loadTest(String browser) throws IOException{
InitializeTestEnv("EE|BizApp");
if(browser.equalsIgnoreCase("Firefox"))
GetBrowser("Firefox");
else if(browser.equalsIgnoreCase("Chrome")){
GetBrowser("Chrome");
}
}
#AfterMethod
public void cleartest() throws InterruptedException{
driver.close();
driver.quit();
driver = null;
}
public void TC001_Phone_First_Acquisition_Journey_PAYM() throws InterruptedException{
URL = EnvDetail.get(Globals.GC_HOME_PAGE);
Map<String,String> TDChoosePlan = null;
TDChoosePlan = getData(appName+Globals.GC_TEST_DATA_SHEET,"ChoosePlan",1);
try{
launchApp(URL);
//driver.navigate().to("javascript:document.getElementById('overridelink').click()");
EEHomePage homePage = PageFactory.initElements(driver, EEHomePage.class);
EEShopPage shopPage = homePage.GetToShopPage();
EEPhoneMatrixPage phonePage = shopPage.GetToPhoneMatrixPage();
EEChoosePlanPage planPage = phonePage.ChoosePhone("NokiaLumia1020"); // Implement select phone
EEAddonsPage addonPage = planPage.SelectPhonesPlan(TDChoosePlan);
EEBasket basketPage = addonPage.GoToBasketPage();
EESecureCheckOut secureChkOutPage = basketPage.GoToSecureCheckOutPage();
secureChkOutPage.ChooseNonExistingCustomer();
EEConfirmation confPage = secureChkOutPage.FillUserRegisterForm(2);
}catch(Exception e){
e.printStackTrace();
}
}
}
My XML looks like this
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name = "EEAutomationTestSuite" verbose="2" parallel = "tests" thread-count="100">
<test name="PAYM Acquisition in Chrome">
<parameter name="browser" value="Firefox"></parameter>
<classes>
<class name="com.testsuite.EETestSuite_01">
</class>
</classes>
</test>
<test name="PAYM Acquisition in FF">
<parameter name="browser" value="Firefox"></parameter>
<classes>
<class name="com.testsuite.EETestSuite_01">
</class>
</classes>
</test>
</suite>
And my code for the Home page is this
*/ public EEShopPage GetToShopPage() throws InterruptedException{
// longWait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(OR.getProperty("wblShopHeader"))));
lblShopHeader = driver.findElement(By.cssSelector(OR.getProperty("wblShopHeader")));
Actions builder = new Actions(driver);
Actions hoverOverRegistrar = builder.moveToElement(lblShopHeader);
hoverOverRegistrar.perform();Thread.sleep(10000);
lnkStartShopping = driver.findElement(By.cssSelector(OR.getProperty("lnkStartShopping")));
mediumWait.until(ExpectedConditions.elementToBeClickable(By.cssSelector(OR.getProperty("lnkStartShopping"))));
lnkStartShopping.click();
return PageFactory.initElements(driver,EEShopPage.class );
}
}
Here is the driver
public static void GetBrowser(String browser){
try{
if (browser.equalsIgnoreCase("firefox")) {
// FirefoxProfile firefoxProfile = new FirefoxProfile();
// File pathToBinary = new File(Globals.GC_FIREFOX_BIN_PATH);
// FirefoxBinary ffBinary = new FirefoxBinary(pathToBinary);
//firefoxProfile.setPreference("webdriver.load.strategy","unstable");
driver = new FirefoxDriver();
} else if (browser.equalsIgnoreCase("iexplorer")){
System.setProperty("webdriver.ie.driver", System.getProperty("user.dir") +
"//resource//drivers//IEDriverServer.exe");
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
driver = new InternetExplorerDriver(capabilities);
} else if (browser.equalsIgnoreCase("chrome")){
System.setProperty("webdriver.chrome.driver", System.getProperty("user.dir") +
"//resource//drivers//chromedriver.exe");
I am just guessing that there is a hover action in the home page, and for one browser it works fine but for the other nothing happens.... is it due focus issue ??
Please let me know how to solve this with an example
I cannot make it out from your code, which constructor you are using for your page Object EEHomePage.
Because, if you are using default constructor then your PageFactory will not be able to initialize your web elements unless they are defined by #FindBy annotation,
PageFactory takes webDriver and Object class as arguments and internally initializes that Object class with provided webDriver.This can be achieved by two ways as below :
1) either define your webElements in your pageObjects using #FindBy annotations as follow :
#FindBy(css=//your locator value here)
private WebElement lblShopHeader;
OR
2) define constructor and initialize your pageobject webdriver by PageFactory provided webdriver as follow :
EEHomeShop(WebDriver driver){
this.driver=driver;
}

Categories

Resources