Подскажите как в селениум джава рэндомно выбирать имя пользователя для отдельного браузера

Есть тест для Логина в юзер аккаунт . Есть два браузера: хром и фф, они запускаются паралельно в saucalbs. Для успешного логина нужно использовать разные юзернейм для каждого браузера.

Для этого я попыталась реализовать метод рендомного выбора юзера и передачи его в метод Логин класса:

Код

    public static String selectRandomUser(){

        String[] users = {"user1", "user2","user3"};
        return users[(int) (Math.random()* users.length)];
    }

Тестовый класс:

public class Login_and_CreateOrder extends RemoteSauceOnDemandBrowser {

@Test(groups = {"TestOnly"}, dataProvider = "browsers")
public void LoginAndCreateOrder(String browser, String version, String os, Method method) throws Exception {

this.createRemoteDriver(browser, version, os, method.getName());
    WebDriver driver = getWebDriver();

    app = new Application(driver);
    

        VisitPage page = VisitPage.getURL(driver);
        this.annotate("Visiting page...");


        app.loginPage().Login_as(RandomDataSelect.selectRandomUser(), configRead.getPassword());
        this.annotate("submit login");

Ошибка: при параллельном запуске первый браузер получает двойной ввод в поле вроде имя пользователя. Например, должно быть “user1”, на деле вводиться “user1user2”. При этом, второй браузер, хром, не получает ни одного вроде и поле логина остаётся пустым.

Детали проекта: селениум вд на джава, с использованием testng,maven. Тест запускается с дженксинс (где и указана комбинация браузеров). Тесты бегают на удаленке saucalabs

Проблема в том, что оба теста используют один и тот же инстанс new Application(driver) так как он сохраняется во внешнюю переменную app.
Для того, чтобы не было двойного ввода, надо чтоб для каждого теста был отдельный инстанс (наприм. Application app = new Application(driver) )

2 лайка

По поводу selectRandomUser() я так понимаю, что задача состоит в том, чтобы для каждого теста выбрать уникального юзера. В этом случае будет удобней и надежней использовать потокобезопасную коллекцию. Например стек:

private static Stack<String> users  = new Stack<>();

static{
users.push("user1");
users.push("user2");
users.push("user3");
}

В тестах можно достать имя юзера так users.pop(). Таким образом оба теста гарантированно получат два разных юзера. При использовании Math.random() такой гарантии, к сожалению, не будет.

2 лайка

Спасибо за ответ. Вы имеете ввиду, что инстанс Application app = new Application(driver) должен быть прописан в каждом тесте, но не в базовом классе? Я так понимаю, что таким же способом нужно инициализировать ConfigRead (содержащий методы чтения даты с проперти фалов) и любой другой инстанс?

Определенно, истанс app должен быть новым в каждом тесте, для того, чтобы запускать тесты параллельно. Что касается ConfigRead, конфиг делают, как правило, один на весь проект, так что имеет смысл инициализировать его только один раз в @BeforeTest например.

Спасибо за советы. Но никак не удаётся достичь идеального результата. Тесты по выбору юзеров из списка не стабильны и иногда повторяется двойной ввод. Может ли это быть связано с кеш?( он нигде не очищается)

Дата провадер стоит как @DataProvider(parallel = true) ?
Никаких вебдрайверов в тесте, если он не статик и обьявлем в BeforeTest, если статик то оборачиваем в ThreadLocal.

True.
Я использую BeforeMethod, далее дата провайдер, далее метод сетап.
Собственно вот код:
public class RemoteTestBase {

public WebDriver driver;

private static String baseUrl;
private RandomDataSelect randomuser;
ConfigFileReader configRead;
private PropertyLoader propertyRead;
public Logger Log = Logger.getLogger(TestBase_Local.class.getName());

private static final String SAUCE_ACCESS_KEY = System.getenv("SAUCE_ACCESS_KEY");
private static final String SAUCE_USERNAME = System.getenv("SAUCE_USERNAME");

@BeforeMethod

@DataProvider(name = "browsers", parallel = true)
public static Object[][] sauceBrowserDataProvider(Method testMethod) throws JSONException {

    String browsersJSONArrayString  = System.getenv("SAUCE_ONDEMAND_BROWSERS");
    System.out.println(browsersJSONArrayString);
    JSONArray browsersJSONArrayObj = new JSONArray(browsersJSONArrayString);

    Object[][] browserObjArray = new Object[browsersJSONArrayObj.length()][3];
    for (int i=0; i < browsersJSONArrayObj.length(); i++) {
        JSONObject browserObj = (JSONObject)browsersJSONArrayObj.getJSONObject(i);
        browserObjArray[i] = new Object[]{browserObj.getString("browser"), browserObj.getString("browser-version"), browserObj.getString("os")};
    }
    return browserObjArray;
}

 void createRemoteDriver(String browser, String version, String os, String methodName) throws Exception {

    DesiredCapabilities capabilities = new DesiredCapabilities();
    Class<? extends RemoteTestBase> SLclass = this.getClass();
    capabilities.setCapability("browserName", browser);
    if (version != null) {
        capabilities.setCapability("browser-version", version);
    }
    capabilities.setCapability("platform", os);

    capabilities.setCapability("name", SLclass.getSimpleName());

    capabilities.setCapability("tunnelIdentifier", "***");


    driver = (new RemoteWebDriver(new URL("http://" + SAUCE_USERNAME + ":" +           SAUCE_ACCESS_KEY + "@ondemand.saucelabs.com:80/wd/hub"), capabilities));

    randomuser = new RandomDataSelect();
    configRead = new ConfigFileReader();
    propertyRead = new PropertyLoader();
    baseUrl = propertyRead.getProperty("site.url");

    getURL();
}



private void getURL () {

    driver.get(baseUrl);
    driver.manage().timeouts().implicitlyWait(40, TimeUnit.SECONDS);
    this.annotate("Visiting HDSupply page..." + driver.toString());
    Log.info("Open a site URL" + "Driver: " + driver.toString());

}

private void printSessionId() {

    String message = String.format("SauceOnDemandSessionID=%1$s job-name=%2$s",
            (((RemoteWebDriver) driver).getSessionId()).toString(), "some job name");
    System.out.println(message);
}



@AfterMethod(description = "Throw the test execution results into saucelabs")
public void tearDown(ITestResult result) throws Exception {

    ((JavascriptExecutor) driver).executeScript("sauce:job-result=" + (result.isSuccess() ? "passed" : "failed"));
    printSessionId();
    driver.quit();
}
void annotate(String text)
{
    ((JavascriptExecutor) driver).executeScript("sauce:context=" + text);
}

}

void createRemoteDriver(String browser, String version, String os, String methodName) throws Exception {

    DesiredCapabilities capabilities = new DesiredCapabilities();
    Class<? extends RemoteTestBase> SLclass = this.getClass();
    capabilities.setCapability("browserName", browser);
    if (version != null) {
        capabilities.setCapability("browser-version", version);
    }
    capabilities.setCapability("platform", os);
    capabilities.setCapability("name", SLclass.getSimpleName());
    capabilities.setCapability("tunnelIdentifier", "***");
    driver = (new RemoteWebDriver(new URL("http://" + SAUCE_USERNAME + ":" + SAUCE_ACCESS_KEY + "@ondemand.saucelabs.com:80/wd/hub"), capabilities));

    randomuser = new RandomDataSelect();
    configRead = new ConfigFileReader();
    propertyRead = new PropertyLoader();
    baseUrl = propertyRead.getProperty("site.url");

    getURL();
}
private void getURL () {

    driver.get(baseUrl);
    driver.manage().timeouts().implicitlyWait(40, TimeUnit.SECONDS);
    this.annotate("Visiting HDSupply page..." + driver.toString());
    Log.info("Open a site URL" + "Driver: " + driver.toString());

}
private void printSessionId() {

    String message = String.format("SauceOnDemandSessionID=%1$s job-name=%2$s",
            (((RemoteWebDriver) driver).getSessionId()).toString(), "some job name");
    System.out.println(message);
}

@AfterMethod(description = "Throw the test execution results into saucelabs")
public void tearDown(ITestResult result) throws Exception {

    ((JavascriptExecutor) driver).executeScript("sauce:job-result=" + (result.isSuccess() ? "passed" : "failed"));
    printSessionId();
    driver.quit();
}
void annotate(String text)
{
    ((JavascriptExecutor) driver).executeScript("sauce:context=" + text);
}

}

И афтерметод

@AfterMethod(description = "Throw the test execution results into saucelabs")
   public void tearDown(ITestResult result) throws Exception {

    ((JavascriptExecutor) driver).executeScript("sauce:job-result=" + (result.isSuccess() ? "passed" : "failed"));
    printSessionId();
    driver.quit();
}
void annotate(String text)
{
    ((JavascriptExecutor) driver).executeScript("sauce:context=" + text);
}

}