Хабрахабр

Как сделать базовый тест-класс для Selenium тестов и выполнить инициализацию через JUnit RuleChain

Этой статьей мы продолжаем серию публикаций о том, как мы автоматизировали в одном из крупных проектов ЛАНИТ процесс ручного тестирования (далее – автотесты) большой информационной системы (далее – Системы) и что у нас из этого вышло.

Как распределить пакеты по проектному дереву? Как эффективно организовать иерархию классов? Эти вопросы всегда стоят при старте новой разработки и на них никогда не хватает времени. Как сделать так, чтобы забыть о мердж-конфликтах при команде в 10 человек?

Источник

Более того, мы ее успешно поддерживаем и постоянно дорабатываем существующие сценарии. В этой статье мы описываем структуру классов и организацию кода, которая позволила нам небольшими силами разработать более полутора тысяч end-2-end UI тестов на базе Junit и Selenium для крупной системы федерального значения.

Здесь вы сможете найти практическое описание структуры иерархии базовых классов автотестов, разбиения проекта по функциональной модели java-packages и шаблоны-образцы реальных классов.

Статья будет полезна всем разработчикам, которые разрабатывают автотесты на базе Selenium.
Эта статья является частью общей публикации, в которой мы описывали, как небольшой командой выстраивали процесс автоматизации UI тестирования и разрабатывали для этого фреймворк на базе Junit и Selenium.

Предыдущие части: 

Концепция разработки автотестов, как было показано в предыдущей статье (Часть 2. Техническая. Архитектура и технический стек. Детали реализации и технические сюрпризы), базируется на идее фреймворка, при которой для всех автотестов предоставляется набор системных функций – они бесшовно интегрируются и дают возможность разработчикам автотестов концентрироваться на конкретных вопросах бизнес-реализации тест-классов.

Фреймворк включает следующие функциональные блоки:

  • Rules – инициализация и финализация тестовых инфраструктурных компонентов как инициализация WebDriver и получение видеотеста. Более подробно описаны далее;
  • WebDriverHandlers – вспомогательные функции для работы с веб-драйвером как исполнение Java Script или доступ к логам браузера. Реализованы как набор статических state-less методов;
  • WebElements – библиотека типовых веб-элементов или их групп, которая содержит требуемую cross-function функциональность и типовое поведение. В нашем случае к такой функциональности относится возможная проверка завершения асинхронных операций на стороне веб-браузера. Реализованы как расширения веб-элементов из библиотек Selenium и Selenide.

Инициализация тестового окружения. Rules

Ключевым классом для всех тест-классов является BaseTest, от которого наследуются все тест-классы. BaseTest-класс определяет Junit «ранер» тестов и используемый RuleChain, как показано далее. Доступ из прикладных тестовых классов к функциям, предоставляемым rule-классами, осуществляется через статические методы rule-классов.   

Образец кода BaseTest представлен на следующей врезке.

@RunWith(FilterTestRunner.class)
public class BaseTest …
}

FilterTestRunner.class – расширение BlockJUnit4ClassRunner, обеспечивает фильтрацию состава исполняемых тестов на базе регулярных выражений по значению специальной аннотации Filter(value = «some_string_and_tag»). Реализация приведена далее.

Timeout – используется для ограничения максимального продолжения тестов. org.junit.rules. Должна устанавливаться первой, так как запускает тест в новой ветке.

Обогащает события данными теста из org.junit.runner. TestLogger – класс, который позволяет тесту логировать события в формате json для использования в ELK-аналитике. Также дополнительно автоматически генерирует события для ELK в формате json для начала-завершения теста с его длительностью и результатом Description.

Обеспечивает быструю проверку, что стенд доступен в принципе. StandStateChecker – класс, который проверяет доступность веб-интерфейса целевого стенда ДО инициализации веб-драйвера.

Используется для индивидуальной настройки «особых» тестов c длительными синхронными обращениями. WaitForAngularCreator – класс, который инициализирует веб-драйвер хэндлер для контроля завершения асинхронных операций ангуляра.

TemporaryFolder – используется для задания уникальной временной папки для хранения файлов для операций загрузки и выгрузки файлов через веб-браузер. org.junit.rules.

DownloaderCreator – класс, который обеспечивает поддержку операций выгрузки во временную директорию файлов, загруженных браузером и записанных через Sеlenoid видеофункцию.

  EnvironmentSaver – класс, который добавляет в Allure-отчет общую информацию о тестовом окружении.

SessionVideoHandler – класс, который выгружает файл видеотеста, при его наличии, и прикладывает к отчету Allure.

Дополнительно класс исполняет набор обязательных для нашего тестирования Java Scripts. DriverCreator – класс, который инициализирует WebDriver (самый главный класс для тестов) в зависимости от установленных параметров – локальный, solenoid или ggr-selenoid. Все правила, которые обращаются к веб-драйверу, должны инициализироваться после этого класса.

BrowserLogCatcher – класс, который считывает Severe сообщения из лога браузера, журналирует их для ELK (TestLogger) и прикладывает к Allure-отчету.

BYTES) ScreenShooter – класс, который для неуспешных тестов снимает скриншот экрана браузера и прикладывает его к отчету аллюр как WebDriverRunner.getWebDriver().getScreenshotAs(OutputType.

Используется для прикладывания файлов выгруженных или загружаемых в систему. AttachmentFileSaver – класс, который позволяет приложить к Allure-отчету набор произвольных файлов, требуемых по бизнес-логике тестов.

Проверяет наличие на экране (после падения) особых модальных окон типа «Произошла системная ошибка №ХХХХХХХХХ», а также системных сообщений типа 404 и тому подобное. FailClassifier – особый класс, который пытается в случае падения теста определить, было ли это падение вызвано инфраструктурными проблемами. Работает через расширение org.junit.rules. Позволяет разделить упавшие тесты на бизнес-падения (по сценарию) или системные проблемы. TestWatcher.#failed метод.

Дополнительно к функциональному тестированию дает возможность определять проблемные и зависающие рест-сервисы при больших нагрузках, а также общую стабильность релиза. PendingRequestsCatcher – еще один особый класс, который пытается дополнительно классифицировать, было ли падение вызвано незавершенными, зависшими или очень длительными рест-сервисами между ангуляром и веб-фронтендом. Для этого класс логирует в ELK все события с зависшими рест-запросами, которые он получает, запуская специальный js в браузере через открытый веб-драйвер.

Шаблон реализации тест-класса 

package autotest.test.<sub-system>;
@Feature("Развернутое название подсистемы как в TMS")
@Story("Развернутое название теста согласно TMS")
@Owner("фамилия автоматизатора вносящего последние правки в тест кейс")
@TmsLink("Номер теста согласно тест линку. Соответствует настроенному шаблону")
public class <Сквозной номер тест кейса>_Test extends BaseTest { /** * Объявляем логин от которой проходит целевой тест **/ Login orgTest; /** Объявляем все логины участвующие в тесте как вспомогательные **/ Login loginStep1; ... Login loginStepN; /** * Здесь перечисляются бизнес-объекты которые требуются для проведения теста - Тестовая сцена * ... для всех требуемых бизнес объектов **/ /** * Инициализация тестовой сцены * Для каждого бизнес объекта необходимо вывести в отчет инициализированное значение * Utils.allure.message("Бизнес имя объекта в контексте тест-сценария", business_object) * Если класс инициализируется как null, то его выводят в отчет с указанием на каком шаге он будет заполнен. * Далее этот тип объекта должен быть дополнительно выведен в отчет в методах preconditions или actions * Utils.allure.message("Номер созданного документа заполняемого на шаге Х", documentNumber) **/ @Step("Инициализация тестовых объектов") private void init(Login login) { some_business_object = // создание требуемого объекта в или вне зависимости от login Utils.allure.message("Бизнес имя объекта в контексте тест-сценария", some_business_object) // ... для всех требуемых бизнес объектов /** Получаем значения вспомогательных логинов */ loginStep1 = LoginFactory.get(_Some_Login_); ... loginStepN = LoginFactory.get(_Some_Login_); } /** * Реализация конкретного теста **/ @Test @Filter("Название теста для использования фильтрации на уровне JUnit") @DisplayName("Развернутое название теста согласно TMS") public void <Сквозной номер тест кейса>_<Полномочие>_<Уникальный_номер_проверки>_Test() { // Получаем значение тестовой организации orgTest = LoginFactory.get(_Some_Login_); // Инициализируем тестовые данные в зависимости от логина init(orgTest); // Выполняем шаги тестовых сценариев-предусловий. Шаги предусловия не должны зависеть от значения логина preconditions(); // Выполняем шаги целевого тестового сценария actions(orgTest); } /** * Выполнение требуемого набора активности для предусловий теста **/ @Step("Предварительные условия") protected void preconditions() { loginStep1.login(); new SomeAction().apply(someTestObject1, ..., someTestObjectN); Utils.allure.message("Получено значение для - Бизнес имя объекта в контексте тест-сценария", someTestObjectN) ... } /** * Метод содержит декларативный перечень операций тестового сценария */ @Step("Шаги теста") protected void actions(Login testLogin) { testLogin.reLogin(); // Выполнение требуемой активности или набора активностей основного теста new SomeAction().apply(someTestObject1, ..., someTestObjectN); }
}

 

Шаблон реализации класса тест-сценария

package autotest.business.actions.some_subsystem; public class SomeAction { // ИНИЦИАЛИЗИРУЕМ СТРАНИЦЫ PageClassA pageA = new PageClassA(); PageClassB pageB = new PageClassB(); @Step("Полное наименование тестового сценария согласно TMS") @Description("Краткое описание тестового сценария согласно TMS") public void apply(someTestObject1, ..., someTestObjectN) { //Шаги сценария по TMS step_1(...); step_2(...); ... step_N(...); } @Step("Наименование шага 1 тестового сценария согласно TMS") private void step_1(...) { pageA.createSomething(someTestObject1);// just as an example create } @Step("Наименование шага 2 тестового сценария согласно TMS") private void step_2(...) { pageA.checkSomething(someTestObject1);// just as an example } ...
}

Реализация класса фильтрации тестов FilterTestRunner

Здесь показана реализация расширения BlockJUnit4ClassRunner для фильтрации тестов на основании произвольных наборов тегов.

/** * Custom runner for JUnit4 tests. * Provide capability to do additional filtering executed test methods * accordingly information that could be provided by {@link FrameworkMethod} */ public class FilterTestRunner extends BlockJUnit4ClassRunner { private static final Logger LOGGER = Logger.getLogger(FilterTestRunner.class.getName()); public FilterTestRunner(Class<?> klass) throws InitializationError { super(klass); } /** * This method should be used if you want to hide filtered tests completely from output **/ @Override protected List<FrameworkMethod> getChildren() { //Получаем экземпляр фильтра, который сравнивает заданный фильтр со значением аннотации @Filter по требуемой логике TestFilter filter = TestFilterFactory.get(); List<FrameworkMethod> allMethods = super.getChildren(); List<FrameworkMethod> filteredMethod = new ArrayList<>(); for (FrameworkMethod method: allMethods) { if (filter.test(method)) { LOGGER.config("method [" + method.getName() +"] passed by filter [" + filter.toString() + "]" ); filteredMethod.add(method); } else { LOGGER.config("method [" + method.getName() +"] blocked by filter [" + filter.toString() + "]" ); } } return Collections.unmodifiableList(filteredMethod); } /** * This method should be used if you want to skip filtered tests but no hide them @Override protected boolean isIgnored(FrameworkMethod method) { … if (filter.test(method)) { return super.isIgnored(method); } else { return true; }} */
}

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

Актуальные вакансии вот здесь. Кстати, будем рады пополнить свою команду.

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»