Падают некоторые тесты при параллельном запуске

День добрый
у меня проблема следующего вида
есть некоторый набор тестов, порядка 40 штук написаны на Java в качестве фреймворка тестов используется TestNG, также используются htmlelements и allure

суть проблемы: в случае если я запускаю свои 40 тестов в 1ин поток
все тесты успешно выполняются

но если я запускаю тесты в несколько потоков, например в 5, то у меня стабильно валятся два теста, два конкретных теста по причинам которые происходить поидее не должны.

отсюда у меня возникают следующие предположения:
1ое, проблема в продукте и при быстром паралельном использовании одной и той же формы, она как то афектит других пользователей (в данном случае другие потоки)
2ое, потоки и соотвественно тесты недостаточно изолированны друг от друга

В связи с чем возникает вопрос, какие меры необходимо принимать для того чтобы гарантировать изолированный запуск тестов в паралельных потоках?

конфигурация тестсьюта такая

     <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
    <suite name="Madnet Testsuite" parallel="classes" thread-count="5">
        <test name="Madnet Ui Tests">
            <classes>
                <class name="login.LoginFormTest"/>
                <class name="login.RegisterFormTest"/>
                <class name="profile.ProfileFormCommonTest"/>mvn
                <class name="profile.ProfileFormAdvertiserTest"/>
                <class name="profile.ProfileFormAdminADvertiserTest"/>
            </classes>
        </test>
    </suite>

запускаются тесты на удалённом Selenium Grid, на FirefoxDriver

  • Показать код создания драйвера.
  • Рассказать, чем запускаете -> чистый testng или maven-surefire-plugin.
  • Задать валидное число потоков, соответствующее кол-ву классов.
  • вот так
        @Step("Инициализация драйвера")
        public static WebDriver driverType(String type) {
        switch (type) {
            case "r.firefox":
                return new RemoteWebDriver(webDriverProperties.getServer(), DesiredCapabilities.firefox());
            case "r.chrome":
                return new RemoteWebDriver(webDriverProperties.getServer(), DesiredCapabilities.chrome());
            default:
                return new FirefoxDriver();
        }
    }
  • запускаю с помощью maven-surefire

  • число потоков соответствует числу классов, в примере из первого поста “эксперимент”

  • Форматируем код.
  • Как думаете, смогут ли читатели связать testng с приведенным кодом? То, что действительно имеет значение, так это связь одной из семейства аннотаций @Before / @After с точками инициализации / убиения драйвера. Из вашего кода этого не отследить.
  • pom бы тогда увидеть.
  • Меня всегда удивляло подобное отношение: какой ответ хочет увидеть ТС, публикуя заведомо противоречивый код, вводящий всех в заблуждение?
  • Статический контекст, как правило, приводит в итоге к одной и той же картине - использованию непотокобезопасных участков с расшариванием состояния драйвера между всеми потоками. Так что опять-таки, ждем полного фрагмента кода.

Меня всегда удивляло подобное отношение: какой ответ хочет увидеть ТС, публикуя заведомо противоречивый код, вводящий всех в заблуждение?

насколько мне известно, количество потоков определённое в конфигурации запуска testng не влияет на изолированность выполняемых классов, поэтому я посчитал этот момент не существенным

вот методы запускающие\останавливающие драйвер

@BeforeMethod
    public void beforeTest() {
        driver = BasePage.driverType(driverType);
        page = new ProfilePage(driver);
    }

    @AfterMethod(alwaysRun = true)
    public void close() {
        page.close();
    }

для метода close

@Step
    public void close() {
        driver.quit();
    }

также кусок расширяющего класса для страниц повторно

public BasePage(WebDriver driver) {
        this.driver = driver;
    }

    @Step("Инициализация драйвера")
    public static WebDriver driverType(String type) {

        switch (type) {
            case "r.firefox":
                return new RemoteWebDriver(webDriverProperties.getServer(), DesiredCapabilities.firefox());
            case "r.chrome":
                return new RemoteWebDriver(webDriverProperties.getServer(), DesiredCapabilities.chrome());
            default:
                return new FirefoxDriver();
        }
    }

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>madnet-ui</groupId>
    <artifactId>madnet-ui</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <allure.version>1.4.11</allure.version>
        <aspectj.version>1.8.5</aspectj.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>2.46.0</version>
        </dependency>

        <dependency>
            <groupId>ru.yandex.qatools.htmlelements</groupId>
            <artifactId>htmlelements-all</artifactId>
            <version>1.14</version>
        </dependency>
        <dependency>
            <groupId>ru.yandex.qatools.allure</groupId>
            <artifactId>allure-testng-adaptor</artifactId>
            <version>${allure.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>junit</groupId>
                    <artifactId>junit</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-all</artifactId>
            <version>1.3</version>
        </dependency>

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-api</artifactId>
            <version>2.41.0</version>
            <type>jar</type>
        </dependency>

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-remote-driver</artifactId>
            <version>2.41.0</version>
            <type>jar</type>
        </dependency>

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-support</artifactId>
            <version>2.41.0</version>
        </dependency>

        <dependency>
            <groupId>com.github.detro.ghostdriver</groupId>
            <artifactId>phantomjsdriver</artifactId>
            <version>1.0.4</version>
        </dependency>

        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>

        <dependency>
            <groupId>ru.yandex.qatools.ashot</groupId>
            <artifactId>ashot</artifactId>
            <version>1.4.12</version>
        </dependency>

        <dependency>
            <groupId>org.fluttercode.datafactory</groupId>
            <artifactId>datafactory</artifactId>
            <version>0.8</version>
            <type>jar</type>
        </dependency>

        <dependency>
            <groupId>com.codeborne</groupId>
            <artifactId>selenide</artifactId>
            <version>2.21</version>
        </dependency>

        <dependency>
            <groupId>ru.yandex.qatools.matchers</groupId>
            <artifactId>webdriver-matchers</artifactId>
            <version>1.1</version>
        </dependency>

        <dependency>
            <groupId>ru.yandex.qatools.matchers</groupId>
            <artifactId>matcher-decorators</artifactId>
            <version>1.1</version>
        </dependency>


    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.16</version>
                <configuration>
                    <suiteXmlFiles>
                        <suiteXmlFile>tests.xml</suiteXmlFile>
                    </suiteXmlFiles>
                    <testFailureIgnore>true</testFailureIgnore>
                    <argLine>
                        -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
                    </argLine>
                    <systemPropertyVariables>
                        <driverType>r.firefox</driverType>
                        <remoteUrl>http://vradchenko.dev.madnet.ru/</remoteUrl>
                        <!--<serverUrl>http://127.0.0.1:4444/wd/hub</serverUrl>-->
                        <serverUrl>http://virt4-hetz-hv2.madnet.ru:4444/wd/hub</serverUrl>
                    </systemPropertyVariables>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjweaver</artifactId>
                        <version>${aspectj.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <reporting>
        <excludeDefaults>true</excludeDefaults>
        <plugins>
            <plugin>
                <groupId>ru.yandex.qatools.allure</groupId>
                <artifactId>allure-maven-plugin</artifactId>
                <version>2.0</version>
            </plugin>
        </plugins>
    </reporting>

</project>

Дело не в изолированности, а в том, что описанная проблема может быть вызвана множеством факторов. И чем больше информации вы предоставите, тем меньше времени потребуется на ответ. Это же в тему о FAQ и информативности сообщений.

По коду все еще не видно, как объявлен драйвер.

Архитектурно - не понятно, что статический driverType делает в BasePage. Как вы считаете, действительно ли абстрактная пейджа - подходящее место для инициализации драйвера? Причем, здесь же присутствует конструктор, который тот же самый драйвер получает откуда-то извне, и сохраняет на уровне instance var. Где тогда содержатся методы Before / After?

Ввиду того, что вы параллелите по классам, а драйвер создаете перед каждым методом, осознаете ли вы, что все методы в пределах класса будут выполнены в одном потоке? Хотелось бы тогда еще взглянуть на конфигурацию самого грида. Какие стоят ограничения на макс. число браузеров / инстансов для ноды?

Заметил еще, что в pom промелькнул thread-count до редактирования. Это тоже был эксперимент, или все же вы пробовали задавать потоки и на уровне xml, и в самом плагине?

Почему версии selenium отличаются? Большинство зависимостей в pom уже устаревшие.

Еще не совсем ясно, какой версии у вас testng. Вы его явно не подключаете. Значит он тянется из одной из зависимостей (allure / selenide), где они могут быть, к слову, разными.

У seleinde есть встроенный механизм получения драйвера.

По делу, я бы рекомендовал вначале разобраться с архитектурными аспектами и вынести инициализацию драйвера из абстрактной пейджи. Если есть статика, она должна быть потокобезопасной. Конфигурация грида не должна противоречить конфигурации testng в связке с драйвером. Посмотрите готовые примеры связки selenide-allure. А еще лучше - создайте тестовый проект с базовой структурой, подключите чистый testng / грид. И потренируйтесь в скейлинге на примитивных тестах, безо всяких 3rd party фреймворков. Когда поймете, как это работает, тогда уж и добавляйте разные фреймворки. По крайней мере в случае ошибок, вы сразу поймете, откуда они возникают. А на данный момент у вас слишком много условий, которые могли привести к такому поведению. К тому же, вы еще не показали стектрейс. Возможно проблема лишь в каком-то совершенно несвязанном с масштабированием runtime exception.

1 лайк

Попробую поправить ваши замечания, и вернусь позже с новостями, спасибо.

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

Походу мне следует поработать над архитектурой моих автотестов.

Я перевел выполнение тестов с FirefoxDriver на ChromeDriver тесты в многопоточном запуске выполняются без косяков и быстрее на 30% чем на Firefox. В общем то этот шаг окончательно решил мою проблему, хотя я так и не выяснил что именно её вызывает.