Удаленка для jenkins+selenide+selenoid+allure+docker спецов на 2-3 часа в день. 100% remote! Присоединиться к проекту

Путаются названия тестов в TeamCity при параллельном запуске

gradle
team-city
java
testng
selenium
webdriver
Теги: #<Tag:0x00007fedbc62fe10> #<Tag:0x00007fedbc62fcd0> #<Tag:0x00007fedbc62faa0> #<Tag:0x00007fedbc62f8c0> #<Tag:0x00007fedbc62f780> #<Tag:0x00007fedbc62f640>

(Aleks) #1

Java + Selenium + TestNg + Gradle

Добрый день, запускаю тесты в TeamCity в 2 потока, при выводе результатов они определяются в неправильный package/suite. В build log так же творится вакханалия, вижу как идет тест1, а названия у него от теста2.
Вот так выглядит testng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="MySuiteName">
    <test name="MyTest" parallel="classes" thread-count="2">
        <classes>
            <class name="ru.company.tests.operator.Operator_Other_Checks" />
            <class name="ru.company.tests.operator.Operator_Call_Back" />
    </test>
</suite>

Например тест Operator_Call_Back.main001 при последовательном запуске попадает в директорию
MySuiteName: MyTest: ru.company.tests.operator,
при параллельном запуске попадает в директорию с названием
MySuiteName: MyTest: ru.company.tests.operator.Operator_Call_Back: ru.company.tests.operator

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

public class TestNgGroup implements  IInvokedMethodListener{
    private WebDriver active_driver;
    private int pull_size = 1;
    private HashMap<Integer,WebDriver> drivers_pull = new HashMap<>();
    private String methodName = "";
    private String className = "";
    private static final ThreadLocal<MySoftAssert> softAssert = new ThreadLocal<>();


    public TestNgGroup() {
    }

    @Override
    public void beforeInvocation(final IInvokedMethod method, final ITestResult testResult) {

    }

    @Override
    public void afterInvocation(final IInvokedMethod method, final ITestResult testResult) {
        if (method.isTestMethod()) {
            try {
                getAssert().assertAll();
            } catch (AssertionError e) {
                if (testResult.getStatus() == ITestResult.FAILURE) {
                    e.printStackTrace();
                }else {
                    testResult.getTestContext().getPassedTests().removeResult(testResult.getMethod());
                    testResult.setStatus(TestResult.FAILURE);
                    testResult.setThrowable(e);
                }
            }
            softAssert.remove();
        }
    }

    @BeforeClass (alwaysRun = true)
    public void setUpMainClass() {
        System.out.println("BeforeClass");
        for (int i=0; i < pull_size; i++) {
            WebDriver drv  = SDK.init_driver_chrome(screen_x, screen_y);
            System.out.println("Браузер " + (i+1) + " из " +pull_size + " запущен");
            drivers_pull.put(i, drv);
        }
        active_driver = drivers_pull.get(0);   //выбирает первый активный драйвер, нужно если нет вначале setActiveDriver
    }

    @BeforeMethod (alwaysRun = true)
    public void setUpMainMethod(ITestContext result, Method method) {
        System.out.println("BeforeMethod");
        methodName = method.getName();
        className = this.getClass().getName();
        if (softAssert.get() == null) {
            softAssert.set(new MySoftAssert(active_driver, className, methodName));
        }
    }

    @AfterMethod (alwaysRun = true)
    public void finishMainMethod(ITestResult testResult) {
        System.out.println("AfterMethod");
        System.out.println("Finished url - " + active_driver.getCurrentUrl());
        if (testResult.getStatus() == ITestResult.FAILURE) {
            SDK.TakeScreenshot(active_driver, className, methodName);
        }
    }


    @AfterClass(alwaysRun = true)
    public void finishMainClass() {
        System.out.println("AfterClass");
        Collection<WebDriver> obj = drivers_pull.values();
        for (WebDriver drv : obj) {
            try {
                drv.quit();
                System.out.println("quite driver");
            }catch (NullPointerException e){
                System.out.println("NullPointerException quite driver");
            }
        }
    }

    public void setActiveDriver(int i){
        active_driver = drivers_pull.get(i);
        if (softAssert.get() == null){
            softAssert.set(new MySoftAssert(active_driver, className, methodName));
        }else {
            softAssert.get().init(active_driver, className, methodName);
        }
    }

    public WebDriver getDriver(){
        return active_driver;
    }

    public String getClassName() {
        return className;
    }

    public String getMethodName() {
        return methodName;
    }

    public MySoftAssert getAssert() {
        return softAssert.get();
    }

    public void setPull_size(int pull_size1) {
        pull_size = pull_size1;
    }

    public void restart_driver(int drivercode){
        WebDriver drv = drivers_pull.get(drivercode);
        drv.quit();
        drv  = SDK.init_driver_chrome(screen_x, screen_y);
        drivers_pull.replace(drivercode, drv);
        System.out.println("Браузер " + (drivercode+1) + " перезапущен");
    }

Так же иногда тесты в TeamCity отображаются, как запущенный два раза и в отчет могут не попасть.

Что нужно сделать чтобы тесты перестали путаться? уже всю голову сломал.


(Nik Sidorenko) #2

По-первым впечатлениям - в базовом классе много всего.

  1. beforeInvocation и afterInvocation я бы рекомендовал вынести в отдельный Listener
  2. для менеджмента параллельных driver-ов обычно используют ThreadLocal ()
  3. для правильного именования тестов надо использовать тот же подход с ThreadLocal и имплементацию класса ITest (implements ITest)

Не совсем понимаю чем вызвана потребность использования MySoftAssert? Была какая-то проблема с тем что после падения одного теста остальные не запускались?

+ Ко всему у TeamCity есть небольшая бага связанная с неправильным отображением количества тестов при параллельном запуске.

Я никогда не пользовался Gradle. Как он запускает тесты в TestNg и как потом отчёт от TestNg отдает?
Если есть возможность посмотреть отчет TestNg отдельно, то нужно убедится, что в нём всё верно, чтобы исключить проблему в TestNg и искать проблему в интерпретации отчёта TestNg из Gradle в TeamCity


(Aleks) #3

1,2,3) Чтобы исключить проблему в базовом классе я его убрал и всю подготовку перенес в сами тесты. Но названия директорий так и продолжают путаться.
Что характерно драйвера не теряются и тесты проходят хорошо, скриншоты делаются в нужных местах.
Потом сделал 3 класса простых тестов, где идет только печать результатов, тот же результат директории в TeamCity запутаны.

  1. Касмотный софт ассерт был приделан для снятия скриншотов и проверки большого количества условий с копированием результатов assertions.

  2. В градле запускается таской, отчетов мне хватает от teamcity.

task testSuite(type: Test) {
    useTestNG() {
        configFailurePolicy 'continue'
        suites 'src/test/resources/testng.xml'
    }
    testLogging {
        events "started", "passed", "skipped", "failed", "standardOut", "standardError"
        exceptionFormat "full"
    }
}

Такое ощущение, что проблема в TeamCity, но не пойму какая


(Aleks) #4

В общем это бага TeamCity, которую еще не починили
https://youtrack.jetbrains.com/issue/TW-51934