Как обезопасить драйвер в несколько потоков с помощью ThreadLocal

Подскажите как обезопасить драйвер в несколько потоков с помощью ThreadLocal.

Как лучше поступить - создать какой нибудь DriverLoader.class в котором Webdriver будет ThreadLocal переменной, или сделать сам инстанс класса ThreadLocal’ом. Как подружить с TestNG / JUnit

Буду признателен за кусочки кода.

Ну TestNG сам по себе потокобезопасный. Т.е. если вы пользуетесь наследованием aka Tests extends BaseTest, в котором собственно и создаете инстансы драйвера, то ThreadLocal вообще не нужен. Если же драйвер статический, то его надо поместить в контейнер:

private static final ThreadLocal<WebDriver> DRIVER = new ThreadLocal<>();

Ну и геттер соответствующий:

public static WebDriver getDriver() {
    return DRIVER.get();
}

Лучше все это дело помещать в раннере, который отвечает за создание инстансов драйверов. В случае с наследованием, можно это делать в BeforeMethod, к примеру:

@BeforeMethod
public void setUp() {
    if (DRIVER.get() == null) {
        DRIVER.set(new FirefoxDriver());
    }
}

@AfterMethod
public void tearDown() {
    if (DRIVER.get() != null) {
        DRIVER.remove();
    }
}
3 лайка

с одним только нюансом, лучше new InheritableThreadLocal() если запуск будет производиться на том же TeamCity или других CI

1 лайк

Не совсем понял, зачем тут нужен InheritableThreadLocal и как это связано с CI. Можно конкретный пример? Интересует именно архитектурная составляющая, при которой необходимо хэндлить чайлд потоки.

Только мигрировал с JUnit на TestNG и не совсем понимаю его потокобезопасности, так как в JUnit с этим никак.

Есть абстрактный класс BaseTest, есть класс DriverProvider который отдает определенный драйвер в зависимости от внешних системных переменных, которые передаются в качества аргументов в командной строке мавену. Для того что бы засетить драйвер в BaseTest - я создаю объект класса DriverProvider и вызываю метод создания дравера.

Как мне лучше поступать в таком случае? Не хотелось бы загромождать класс BaseTest всей логикой создания драйвера с необходимыми мне параметрами. Логично ли создавать объект класса DriverProvider перед каждым методом?

Когда вы параллелите ваши тесты, TestNG пускает их в отдельных потоках (ради эксперимента, выводите в консоль thread id). Если вы пользуетесь наследованием, логично, что все новые нестатические объекты, созданные в пределах конкретного потока, никогда не выйдут за его пределы.

Учитывая факт создания драйвера внутри отдельного потока, в случае отсутствия статики вы всегда получите уникальный инстанс.

It’s up to you. Смотря, как хотите параллелить.

Каждый класс с тестами пускать в отдельный поток - отдельный браузер.
Сейчас это паралелится так:

                 <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.17</version>
                    <configuration>
                        <testFailureIgnore>false</testFailureIgnore>
                        <argLine>
                            -javaagent:${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar
                        </argLine>
                        <properties>
                            <property>
                                <name>listener</name>
                                <value>ru.yandex.qatools.allure.testng.AllureTestListener</value>
                            </property>
                        </properties>
                        <parallel>classes</parallel>
                        <threadCount>${count.of.threeds}</threadCount>
                        <systemPropertyVariables>
                            <webdriver.driver>${webdriver.driver}</webdriver.driver>
                        </systemPropertyVariables>
                    </configuration>
                    <dependencies>
                        <dependency>
                            <groupId>org.aspectj</groupId>
                            <artifactId>aspectjweaver</artifactId>
                            <version>${aspectj.version}</version>
                        </dependency>
                    </dependencies>
                </plugin>

Но я так понимаю можно паралелить средствами TestNG

Через testng.xml все делается очень просто.

2 лайка