Подскажите пожалуйста. Как правильно спроектировать автотесты используя Page Factory. В автоматизации я новичок, поэтому строго не судите)
Создал базовый класс TestBase, где описал Before test: объявляю и инициализирую драйвер, пейджы, открваю сайт, инициализирую класс с переменными.
От базового класса наследуюсь класом Tests, где прописываю все свои тесты.
Отдельно в папке создаю пейджы, где все переменные и методы статические.
Отдельно создаю класс с переменными, они все статические.
Класс с переменными импортирую в пейджи там где надо и использую.
Пейджи импортирую в базовый класс.
Вопросы:
Нужно ли инициализировать пейджи и класс с переменными в базовом классе все сразу в Before test?
Кооректно ли обявлять в классах пейджах и переменных статические переменные и методы, или это как то можно по другому обойти?
Корретно ли я наследовал и импортил?
Какие вообще лучшие практики построения автотестов?
Извините я тут немного не понимал, но до меня наконец-то дошло.
Дело в том, что в программировании Manager-ом обычно называют какой-то вспомогательный класс. В Вашем же случае - это сущность Вашего приложения.
В классе Tests зависимости между тестами быть не должно (dependsOnMethods = {“logIn”}).
Вот это вынесите в класс вашей страницы в какой то метод который будет возвращать текст этого элемента и потом уже дергайте этот метод в тестовом классе.
Идея наследовать все тестовые классы от базового тестового класса, в котором выполняются настройки - это самая стандартная практика, которая в 90% несёт пользу.
В базовом тестовом классе не нужно инициализировать все страницы сразу. По-хорошему в тестовых классах вообще не должно быть инициализации страниц. Этим должны заниматься вспомогательные классы. В идеале инициализированные страницы должны возвращаться из методов. Например, loginPage.logIn() должен возвращать страницу dashBoardPage. Если метод loginPage.logIn() параметризировать и дать возможность передавать данные для логина из теста, то в случае если данные неверны - этот метод должен возвращать LoginPage.
Также в базовом тестовом классе не нужны поля для хранения страниц. Тесты должны быть независимыми и атомарными/самодостаточными. Это означает, что страницы между тестами и тестовыми классами передаваться не должны. Т.е. одна и та же страница не должна использоваться в нескольких тестах.
Насколько я понял в качестве тестового фреймворка Вы используете TestNG. Внимательно изучите, что означают его аннотации. В TestNG существует следующая базовая иерархия тестовых сущностей. Самая маленькая - тестовый method (метод тестового класса). Тестовые методы объединяются в тестовые классы. Далее следует Test, который может состоять из нескольких тестовых классов или тестовых методов разных тестовых классов. Test-ы собираются в Suite. Перепроверьте чего Вы хотели достигнуть используя @BeforeTest аннотацию. @BeforeTest будет выполнятся раз перед TestNG Test. Не перед каждым методом с аннотацией @Test.
Детали инициализации драйвера лучше убрать из базового тестового класса в какой-нибудь DriverManager или DriverFactory. А в базовом тестовом классе обращаться для получения драйвера к DriverManager или DriverFactory. Также не используйте абсолютные пути для указания пути к файлу драйвера - пользуйтесь относительными путями к папке вашего рабочего проекта.
Implicit wait 10 секунд - это многовато. Пользуйтесь explicit wait-ами где это необходимо.
Что Вы проверяете в тесте logIn()? Насколько я понимаю, Вы хотите проверить, что после логина открывается страница dashBoardPage. Если метод loginPage.logIn() будет возвращать страницу dashBoardPage (как было сказано выше), то Вам нужно проверить, что в результате его выполнения вернётся экземпляр (instanseof) этой странице. Button-ами в тесте лучше не оперировать.
Как уже было сказано в посте Какая должна быть правильная структура тестов? - #10 от пользователя ordeh зависимости между тестами - это крайняя мера и если есть возможность их не делать, то лучше не делать. Понятно, что для второго теста Вам нужно залогиниться, как и скорее всего для третьего понадобиться. Это то, что нужно делать в каждом тесте отдельно либо вынести в базовый тестовый класс с аннотацией @BeforeMethod
Тест throws InterruptedException. Такого как по мне быть не должно. Такие эксепшены должны обрабатываться уровнем ниже.
Как уже было сказано в том же посте от @ordeh все локаторы должны быть в классах страниц.
Рекомендую сразу учиться пользоваться более продвинутыми Assert-ами Hamcrest Tutorial
Теперь к пейджам
Для педжей часто тоже создают базовый класс, в котором собирают основные методы и от которого потом наследуют остальные пейджи. В Вашем случае в этот базовый класс уже можно засунуть конструктор с вызовом PageFactory и инициализацией драйвера. Туда же можно перенести поле драйвера и сделать его protected
Драйвера, кстати, в коде тестов быть не должно. По-хорошему драйвер должен быть только в классах страниц.
Старайтесь не использовать тестовые данные (Variables) в коде страниц. Делайте методы страниц параметризируемыми, а данные передавайте из тестов. Например, метод logIn() можно переделать на logIn(String username, string password)
Если вызов метода приводит к переходу на другую страницу, то желательно чтобы метод возвращал экземпляр этой страницы (про это уже говорил чуть ранее)
Внутри пейджовых методов также следует выполнять ожидание завершения действия/загрузки страницы. В Вашем случае после логина, если драйвер сам не дожидается загрузки страницы (такое бывает если нажатие кнопки не ведёт к переходу на другую страницу в браузере = смене URL), надо дождаться пока загрузится dashBoardPage
Общая рекомендация - избавляйтесь от static-ков по-максимуму.
Если это вопросы, то попробую частично ответить.
2. Сделать метод не void а чтобы возвращал новый PageObject. Например, есть Login метод, который логинится. В методе сделать все действия, а в конце - return new MainPage(driver) - код может меняться, в зависимости от того, как устроен framework.
Если используете статический драйвер - можете забыть о параллелизации тестов, это одна из причин.
По другим подробных ответов не имею.
@Valentin_G, @ordeh Как вернуть объект я и так знаю, я имею в виду что если нам после нажатия на кнопку логин не всегда нужно переходить на новую страницу? Например после нажатия должно появится ерор что логин не правильный. Это возможно только явной передачей типа возвращаемого объекта при возвращаемом дженерик типе, ну или городить костыли с интерфейсами.
А что если я скажу что можно паралелить на уровне CI а не стандартным parallel=true, или использовать потокобезопасные контейнеры для хранения драйверов ну или самый банальный ThreadLocal ?
посмотрите примеры - выберите то что понравится
серебряной пули нет
Я постепенно шёл по пути всё большей инкапсуляции (например все данные в файлах ресурсов)
потом сделал шаг назад когда увидел что трачу больше времени на дебаг
что будет удобно на на конретном проекте в конретное время - никто не знает
нужно пробовать и смело отступать если решение не удачное.
Для такого я пишу следующий шаг в тесте, который дожидается элемента, где находится данное сообщение об ошибке и валидирую его - если я в тесте проверяю конкретно это сообщение. Если какой-то эррор и тест не прошел дальше, хотя должен был - тест фейлится.
По поводу параллелизации на уровне СИ или потокобезопасные контейнеры - про это не могу сказать ничего, никогда не использовал.