Параллельное выполнение TestNG с одним экземпляром драйвера - PullRequest
0 голосов
/ 03 июля 2019

В моем наборе тестов у меня есть базовый класс, в котором я объявляю статический WebDriver, который затем генерируется как ChromeDriver, FirefoxDriver и т. Д., В методе, который открывает базовый URL-адрес. Этот метод используется в моем BeforeMethod во всех моих тестовых примерах, поэтому один статический экземпляр драйвера используется при каждом выполнении теста и во всем диапазоне повторно используемых методов, используемых в тестовых примерах (например, метод входа в систему).

Кажется, это создает проблему, сейчас я пытаюсь ввести параллельное выполнение, так как мне кажется, что мне нужны отдельные экземпляры драйвера для любых сценариев, которые я хочу запустить одновременно, чтобы избежать вмешательства потоков. Можно ли как-нибудь заставить мои скрипты работать параллельно без реструктуризации всего моего пакета, чтобы каждый скрипт был написан совершенно независимо?

Я попытался вместо этого объявить массив WebDrivers, а затем выбрать определенный индекс на основе параметра, отправленного из XML стартового набора, но это не помогло. Второй браузер открывается, но в нем ничего не происходит.

Это мой Базовый класс:

public class Base {


public static WebDriver driver = null;

//Input client under test
public static final String Client = "Client1";

//Input default environment under test
public static final String DefaultEnvironment = "Chrome_Hub";


//CALL WEB BROWSER AND OPEN WEBSITE
public static void openURL(String environment) throws InterruptedException, IOException {

    try{

        if(environment.equals("Chrome_Hub")) {
            System.setProperty("webdriver.chrome.driver", "/Users/rossdonohoe/Desktop/SeleniumJava/Drivers/chromedriver");
            driver = new ChromeDriver();
        }
        if(environment.equals("Firefox_Hub")) {
            System.setProperty("webdriver.gecko.driver", "/Users/rossdonohoe/Desktop/SeleniumJava/Drivers/geckodriver");
            driver = new FirefoxDriver();
        }

        driver.get(DataFinder.ReadData("front end url"));


    }
    catch(Exception E) {
        E.printStackTrace();
    }
}
}

Вот пример сценария:

public class LoginLogoutScript extends Base {


  @Test (priority = 2)
  public void login() throws InterruptedException, IOException {
        LoginLogout.loginFrontEnd();
        Assert.assertTrue(driver.getPageSource().contains("My Account") || driver.getPageSource().contains("My Dashboard"));
  }

  @Parameters({ "Environment" })
  @BeforeClass
  public void setUp(@Optional(DefaultEnvironment) String Environment) throws InterruptedException, IOException {
      Base.openURL(Environment);
  }

  @AfterClass public void tearDown() { 
      Base.driver.quit(); 
  }

}

Вот метод, вызываемый в этом скрипте:

public class LoginLogout extends Base {

    public static void loginFrontEnd () throws InterruptedException, IOException {
        Thread.sleep(5000);
        WebDriverWait wait = new WebDriverWait(driver, 10);
        WebElement login2 = wait.until(ExpectedConditions.elementToBeClickable(By.linkText(DataFinder.ReadData("sign in link"))));
        ((JavascriptExecutor)driver).executeScript("arguments[0].click();", login2);
        WebDriverWait wait = new WebDriverWait(driver, 15);
        wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("email")));
        driver.findElement(By.id("email")).sendKeys(DataFinder.ReadData("username entry"));
        driver.findElement(By.id("pass")).sendKeys("I$$\"Cnewton1");
        Thread.sleep(5000);
        driver.findElement(By.id("send2")).click();
    }
}

Вот еще один скрипт:

@Listeners(CustomListener.class)
public class CreateDeleteCustomerAccountScript extends Base {

  @Test (priority = 1)
  public void createAccount() throws InterruptedException, IOException {

        WebDriverWait wait = new WebDriverWait(driver, 15);
        wait.until(ExpectedConditions.visibilityOfElementLocated(By.partialLinkText(DataFinder.ReadData("navigate to register account 1"))));
        driver.findElement(By.partialLinkText(DataFinder.ReadData("navigate to register account 1"))).click();

        driver.findElement(By.cssSelector(DataFinder.ReadData("navigate to register account 2"))).click();

        driver.findElement(By.name("firstname")).sendKeys("Testy");
        driver.findElement(By.name("lastname")).sendKeys("McTester");
        driver.findElement(By.cssSelector("#email_address")).sendKeys(Misc.generateRandomString() + "@thepixel.com");
        driver.findElement(By.name("password")).sendKeys("I$$\"Cnewton1");
        driver.findElement(By.name(DataFinder.ReadData("password confirmation"))).sendKeys("I$$\"Cnewton1");

            //verify account created
        Thread.sleep(5000);
        Assert.assertTrue(driver.findElement(By.tagName("body")).getText().contains(DataFinder.ReadData("account created message")));
  }

  @Parameters({ "Environment" })
  @BeforeClass
  public void setUp(@Optional(DefaultEnvironment) String Environment) throws InterruptedException, IOException {
      Base.openURL(Environment, "front end");
  }

  @AfterClass public void tearDown() { 
      Base.driver.quit(); 
  }
}

Вот мой XML-файл:

<?xml version="1.0" encoding="UTF-8"?>

<suite name="FullRegressionSuite" parallel="tests" thread-count="2">
<listeners>

</listeners>

  <test name="Test1">
   <parameter name ="DriverNo" value="1"/>
    <classes>
      <class name="userManagement.LoginLogoutScript"/>
    </classes>
  </test>
  <test name="Test2">
    <parameter name ="DriverNo" value="2"/>
    <classes>
      <class name="userManagement.CreateDeleteCustomerAccountScript"/>"/>
    </classes>
  </test>

       <!-- Test -->
</suite> <!-- Suite -->

Ответы [ 2 ]

1 голос
/ 03 июля 2019

Если вы выполняете свои тесты через Maven, вы можете пересмотреть Fork Options , чтобы каждый поток TestNG выполнялся в отдельном JVM экземпляре

<forkCount>2</forkCount> <!- amend this to be equal to the number of TestNG threads -->
<reuseForks>false</reuseForks>

Однако это только маскирует проблему, тем большее ограничение заключается в том, что вы используете статический модификатор для экземпляра WebDriver , это определенно нарушает Рекомендации по параллельному тестированию

0 голосов
/ 03 июля 2019

Вы можете использовать потоковый веб-драйвер, как указано ниже.

public class Base {


public static ThreadLocal<WebDriver> driver = new ThreadLocal<>();

//Input client under test
public static final String Client = "Client1";

//Input default environment under test
public static final String DefaultEnvironment = "Chrome_Hub";


//CALL WEB BROWSER AND OPEN WEBSITE
public static void openURL(String environment) throws InterruptedException, IOException {

    try{

        if(environment.equals("Chrome_Hub")) {
            System.setProperty("webdriver.chrome.driver", "/Users/rossdonohoe/Desktop/SeleniumJava/Drivers/chromedriver");
            driver.set(new ChromeDriver());
        }
        if(environment.equals("Firefox_Hub")) {
            System.setProperty("webdriver.gecko.driver", "/Users/rossdonohoe/Desktop/SeleniumJava/Drivers/geckodriver");
            driver.set(new FirefoxDriver());
        }

        driver.get(DataFinder.ReadData("front end url"));


    }
    catch(Exception E) {
        E.printStackTrace();
    }
}
}

И вы можете использовать метод driver.get (), чтобы получить его экземпляр.

public class LoginLogoutScript extends Base {


  @Test (priority = 2)
  public void login() throws InterruptedException, IOException {
        LoginLogout.loginFrontEnd();
        Assert.assertTrue(driver.getPageSource().contains("My Account") || driver.get().getPageSource().contains("My Dashboard"));
  }

  @Parameters({ "Environment" })
  @BeforeClass
  public void setUp(@Optional(DefaultEnvironment) String Environment) throws InterruptedException, IOException {
      Base.openURL(Environment);
  }

  @AfterClass public void tearDown() { 
      Base.driver.get().quit(); 
  }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...