如何使用ThreadLocal和PageFactory概念在selenium中执行并行执行



我正在使用线程本地驱动程序,但在并行执行时仍然无法实现线程安全。

  • 2 chrome浏览器启动
  • 双击注册链接
  • 然后只有一个浏览器点击登录,同一个浏览器再次尝试点击登录链接并得到错误
  • 其他浏览器窗口根本没有点击登录

我的驱动程序出厂级别是

public class DriverFactory {
//Singleton design Pattern
//private constructor so that no one else can create object of this class
private DriverFactory() {

}
private static DriverFactory instance  = new DriverFactory();
public static DriverFactory getInstance() {
return instance;
}

//factory design pattern --> define separate factory methods for creating objects and create objects by calling that methods
ThreadLocal<WebDriver> driver = new ThreadLocal<WebDriver>();
public WebDriver getDriver() {
return driver.get();
}
public void
setDriver(WebDriver driverParm) {
driver.set(driverParm);
System.out.println("Before Test Thread ID: "+Thread.currentThread().getId());
}

public void closeBrowser() {
driver.get().quit();
System.out.println("After Test Thread ID: "+Thread.currentThread().getId());
driver.remove();
}
}

我的浏览器工厂类是

public class BrowserFactory {
//create webdriver object for given browser
public WebDriver createBrowserInstance(String browser) throws MalformedURLException {
WebDriver driver = null;
//RemoteWebDriver driver = null;

if(browser.equalsIgnoreCase("Chrome")) {
WebDriverManager.chromedriver().setup();
System.setProperty("webdriver.chrome.silentOutput", "true");
ChromeOptions options = new ChromeOptions();
options.addArguments("--incognito");
DriverFactory.getInstance().setDriver(driver);
driver = new ChromeDriver(options);
}else if (browser.equalsIgnoreCase("firefox")) {
WebDriverManager.firefoxdriver().setup();
FirefoxOptions foptions = new FirefoxOptions();
foptions.addArguments("-private");

//driver = new RemoteWebDriver(new URL("http:192.168.225.219:4444/wd/hub"), DesiredCapabilities.firefox());

driver = new FirefoxDriver(foptions);
} if (browser.equalsIgnoreCase("ie")) {
WebDriverManager.iedriver().setup();
InternetExplorerOptions iOptions = new InternetExplorerOptions();
iOptions.addCommandSwitches("-private");
driver = new InternetExplorerDriver(iOptions);
}
return driver;
}
}

我的TestBase类是

public class TestBase extends ActionEngine {
public WebDriver driver;
public BrowserFactory browserFactory;
String browserName = null;
//static ExtentReports extent = ExtentManager.getInstance();
/*public WebDriver getDriver() {
driver=DriverFactory.getInstance().getDriver();
return driver;
}*/

@BeforeMethod
public void LaunchApplication() throws Exception {
browserName = PropertiesOperations.getPropertyValueByKey("browser");
browserFactory = new BrowserFactory();
DriverFactory.getInstance().setDriver(browserFactory.createBrowserInstance(browserName));
//driver = browserFactory.initBrowser(browserName);
//driver = DriverFactory.getInstance().getDriver();
String url = PropertiesOperations.getPropertyValueByKey("url");
DriverFactory.getInstance().getDriver().get(url);
Thread.sleep(5000);
DriverFactory.getInstance().getDriver().manage().window().maximize();
System.out.println("Browser maximized");
DriverFactory.getInstance().getDriver().manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}
@AfterMethod
public void tearDown() {
DriverFactory.getInstance().closeBrowser();
}
//@AfterMethod
public void assignDevice() {
ExtentFactory.getInstance().getExtent().assignDevice(browserName);
}
//@AfterMethod
public void assignAuthor() {
ExtentFactory.getInstance().getExtent().assignAuthor("Mayank Mishra");
}
}

TestNG.xml

<suite name="Demo Web App test suite" parallel="methods" thread-count="2" >
<listeners>
<listener
class-name="reusableComponents.ListenersImplementation" />
<listener
class-name="reusableComponents.TestRetryAnalyzerListener" />
</listeners>
<test name="LoginTests">
<classes>
<class name="Tests.LoginTest" />
</classes>
</test> <!-- Test -->
<!--<test name="DataDriven Tests">
<classes>
<class name="Tests.TestCase" /> 
</classes>
</test>--> <!-- Test -->
</suite> <!-- Suite -->

页面类别为

public class RegistrationPage {
private WebDriver driver;
//Asserssion asserssion;
public RegistrationPage(WebDriver driver) {
//driver=DriverFactory.getInstance().getDriver();
this.driver = driver;
PageFactory.initElements(driver, this);
}
@FindBy(linkText = "ACCOUNT")
private WebElement accountLink;
@FindBy(linkText = "Register")
private WebElement registerLink;
@FindBy(linkText = "Log In")
private WebElement loginLink;
@FindBy(xpath = "//h3[contains(text(),'Contact Information')]/following-sibling::a")
private WebElement editAccountInfo;
@FindBy(xpath = "//a[contains(text(),'Forgot Your Password?')]")
private WebElement forgotPasswordLink;
//public static Logger logger = Logger.getLogger(RegistrationPage.class.getName());
//public static Logger log = Logger.getLogger("");
public  void clickAccount() throws InterruptedException {
Thread.sleep(5000);
accountLink.click();
//loginLink.click();
//forgotPasswordLink.click();
//loginLink.click();
//driver=DriverFactory.getInstance().getDriver();
//driver.findElement(By.linkText("ACCOUNT")).click();
ExtentFactory.getInstance().getExtent().log(INFO,"Click on account link");
//Log.info("clicked on account link");
}

public  void clickLoginLink() throws InterruptedException {
//Log.info("Click on login link");
Thread.sleep(5000);
loginLink.click();
ExtentFactory.getInstance().getExtent().log(INFO,"Click on login link");
}
public void clickForgotPasswordLink() throws InterruptedException {
//Log.info("Click on login link");
Thread.sleep(5000);
forgotPasswordLink.click();
ExtentFactory.getInstance().getExtent().log(INFO,"Click on forgot password link");
}

}

我的测试班是

public class LoginTest extends TestBase {
LoginPage loginPage;
RegistrationPage registrationPage;
ExcelOperations excel = new ExcelOperations("validLogin");
ExcelOperations excel2 = new ExcelOperations("invalidLogin");

//Dataprovider method --> return object array
@DataProvider(name = "validLogin")
public Object[][] testDataSupplier1() throws Exception {
Object[][] obj = new Object[excel.getRowCount()][1];
for (int i = 1; i <= excel.getRowCount(); i++) {
HashMap<String, String> testData = excel.getTestDataInMap(i);
obj[i - 1][0] = testData;
}
return obj;
}
@DataProvider(name = "invalidLogin")
public Object[][] testDataSupplier2() throws Exception {
Object[][] obj = new Object[excel2.getRowCount()][1];
for (int i = 1; i <= excel2.getRowCount(); i++) {
HashMap<String, String> testData = excel2.getTestDataInMap(i);
obj[i - 1][0] = testData;
}
return obj;
}
@BeforeMethod
public void loadClass() {
//loginPage = PageFactory.initElements(DriverFactory.getInstance().getDriver(), LoginPage.class);
registrationPage = PageFactory.initElements(DriverFactory.getInstance().getDriver(), RegistrationPage.class);
}
@Test(dataProvider = "invalidLogin", description = "login with invalid password")
public void loginTest_01(Object obj1) {
try {
System.out.println("in method1
registrationPage.clickAccount();
System.out.println("clicking on login link");
registrationPage.clickLoginLink();

} catch (Exception e) {
System.out.println(e.getMessage());
Assert.fail("Cant do login");
}
}
@Test(dataProvider = "validLogin", description = "login with valid password")
public void loginTest_02(Object obj2) {
try {
System.out.println("in method2");
registrationPage.clickAccount();
System.out.println("clicking on login link");
Thread.sleep(5000);
registrationPage.clickLoginLink();

} catch (Exception e) {
System.out.println(e.getMessage());
Assert.fail("Cant do login");
}
}
}

下面的类的清理版本应该基本上解决了您的问题

import io.github.bonigarcia.wdm.WebDriverManager;
import java.util.Optional;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.ie.InternetExplorerOptions;
public final class DriverFactory {
private DriverFactory() {
//defeat instantiation
}
private static final ThreadLocal<WebDriver> driver = new ThreadLocal<>();
private static final String ERROR_MSG = "WebDriver instance NOT setup for current thread";
public static WebDriver getDriver() {
return Optional.ofNullable(driver.get())
.orElseThrow(() -> new IllegalStateException(ERROR_MSG));
}
public static void setupWebDriver(String browserFlavor) {
driver.set(createBrowserInstance(browserFlavor));
}
public static void closeBrowser() {
Optional.ofNullable(driver.get())
.orElseThrow(() -> new IllegalStateException(ERROR_MSG))
.quit();
driver.remove();
}
private static WebDriver createBrowserInstance(String browser) {
browser = Optional.ofNullable(browser).orElse("chrome").toLowerCase();
switch (browser) {
case "chrome":
WebDriverManager.chromedriver().setup();
System.setProperty("webdriver.chrome.silentOutput", "true");
ChromeOptions options = new ChromeOptions();
options.addArguments("--incognito");
return new ChromeDriver(options);
case "firefox":
WebDriverManager.firefoxdriver().setup();
FirefoxOptions foptions = new FirefoxOptions();
foptions.addArguments("-private");
return new FirefoxDriver(foptions);
case "ie":
WebDriverManager.iedriver().setup();
InternetExplorerOptions iOptions = new InternetExplorerOptions();
iOptions.addCommandSwitches("-private");
return new InternetExplorerDriver(iOptions);
default:
throw new IllegalArgumentException("Browser flavor [" + browser + "] is NOT supported");
}
}
}

下面是你的基类现在的样子:

import java.time.Duration;
import java.time.temporal.ChronoUnit;
import org.openqa.selenium.WebDriver;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
public class TestBase {
@BeforeMethod
public void LaunchApplication() {
String browserName =  "chrome";
DriverFactory.setupWebDriver(browserName);
String url = "https://www.somedomain.com";
WebDriver driver = DriverFactory.getDriver();
driver.get(url);
driver.manage().window().maximize();
System.out.println("Browser maximized");
driver.manage().timeouts().implicitlyWait(Duration.of(30, ChronoUnit.SECONDS));
}
@AfterMethod
public void tearDown() {
DriverFactory.closeBrowser();
}
}

有了上面两个清理过的类,现在就不需要一个无关的BrowserFactory了。

每当您需要访问当前@Test注释测试方法的WebDriver对象时,您只需要调用DriverFactory.getDriver()

注意:我使用的是v4.4.0中的selenium api

最新更新