Доброго времени суток!
Коллеги, в очередной раз необходима помощь.
Имеется TestNG и сьюта ALL_TESTS.xml.
По результатом выполнения всей сьюты ALL_TESTS.xml, она в алюре помечается как BROKEN с сообщением Test suite was interrupted, some test cases may be lost, при етом Stacktrace - пуст. Все тесты, которые включены в сьюту - PASSED, скриншоты/файлы присутствуют. С чем такое поведение может быть связано, куда смотреть?
Засетил thread-count=“1”… не помогло. Может дело в кастомном листнере…? Я листнер подключал аннотацией над тестовым классом, мож надо еще в сьюте продублировать…?
Не выключает многопоточность. Уберите вообще параметры потоков и parallel.
Да и листенер пока отключите.
Потом, если пройдёт - подключите листенер, а потом параллельность.
Частично нашел решение - помогло наследование от листнера из allure-testng-adaptor (AllureTestListener). Проблема в том, что теперь все результаты тестов - дублируются. Предполагаю, из-за того, что ServiceLoader запускает дефалтовый листнер. Есть возможность отключить дефалтовый листнер и использовать только кастомный?
Покажите свой ThreadLocalPageContainer. Вообще говоря, смахивает на некорректное использование ресурсов в многопоточной среде. У вас даже сам слушатель противоречив. Если вы действительно помещаете ресурсы в ThreadLocal, то почему инициализация происходит перед запуском каждого теста, а cleanup в глубоком onFinish (который уступает лишь afterSuite в последовательности)?
Помимо этого, из официальной документации TestNG следует, что любой Listener имеет глобальную область видимости.
Note that the @Listeners annotation will apply to your entire suite file, just as if you had specified it in a testng.xml file.
Нет смысла аннотировать его над каждым классом, ибо он будет применен ко всем. Подключайте его только на уровне maven-surefire-plugin. Причем только его. Аллюровского слушателя там не должно быть и в помине с определенной версии.
Я старался сделать обычный потокобезопасный контейнер:
package core.utils;
import core.services.SelenideImplPage;
public class ThreadLocalPageContainer {
private static final ThreadLocal<SelenideImplPage> threadLocalPages = new ThreadLocal<>();
public final static SelenideImplPage getThreadLocalPage() {
return threadLocalPages.get();
}
public final static void setThreadLocalPage (SelenideImplPage page) {
threadLocalPages.set(page);
}
}
SelenideImplPage - класс-врапер для селенида (с логированием и прочими мелочами).
Не исключено, т.к. ето моя первая попытка сделеать кастомный листенер, буду презнателен за рекомендации.
Перед запуском каждого теста происходит получение имени данного теста, которое используется для логирования (имя логгера). Т.е. даже при паралельном выполнении можно просмотреть лог, грепнув по имени теста, и увидеть процесс выполнения. А в самом конце - “контрольное” закрытие веб драйвера, если по ходу тестов про него забыли.
Да, алюровского листнера там и нет. Спасибо за идею с переносом кастомного листнера в помник. Попробую - отпишусь.
Ну вот вы старались-старались, а надо было вначале почитать, как правильно работать со ThreadLocal. Сам факт того, что вы только добавляете и совсем не чистите свои контейнеры, автоматически указывает на потенциальные утечки памяти и некорректное использование ресурсов. Ввиду того, что TestNG переиспользует потоки, в вашем ThreadLocal наверняка хоронится тонна навсегда потеряных ссылок.
Все равно я пока не пойму вашей архитектурной задумки. Исходя из названия, обертка работает с какой-то пейджой. Но зачем конкретную пейджу помещать в потокобезопасный контейнер, если TestNG уже сам по себе дробит сущности по потокам? Хотя, возможно дело конечно в контексте масштабирования, который привязан к уровню классов. Но опять-таки, не совсем понятно, где и по каким правилам в этой всей цепи происходит инициализация драйвера.
Спасибо, учту. Скорее всего после выполнения теста буду “убивать” ссылку в контейнере.[quote=“ArtOfLife, post:15, topic:11529”]
Исходя из названия, обертка работает с какой-то пейджой.
[/quote]
Возможно наличие “page” в имени класса сбивает с толку… По сути ето класс, который содержит в себе все базовые дейсвия (startDriver, clickOn, goTo…).
Сам веб драйвер создается уже в тестовых классах в зависимости от необходимости: один на все тесты (в аннотации @BeforeClass) ну или в каждом тесте новый. Создание происходит посредством методов “пейджи” - сетится поле класса и WebDriverRunner селенида.
Это говорит о неверно спроектированной архитектуре. Тесты ничего не должны знать о драйвере. Ровно, как и страницы. Все проблемы как правило тянутся из-за жуткого микса доменной логики с низкоуровневой составляющей. Все, что касается драйвера, должно быть вынесено в отдельный модуль.
Базовые действия у вас тоже намиксованы. Логика создания драйвера и управления поведением должны быть разнесены. Страницы не должны заниматься поднятием браузера. Это не их задача.