Функциональные тесты большинством воспринимаются как линейные сценарии: открой страничку, нажми эту кнопку, введи такой-то текст в поле ввода, нажми другую кнопку. Сценарии похожи на то, как действует реальный пользователь. Однако они плохи тем, что требуется повторять много однотипных действий в разных тестах, чтобы попасть в нужное исходное состояние. Если меняется содержимое станицы (например, разметка или классы у элементов), то нужно во все тестах внести соответствующие изменения.
В документации к Selenium описан другой подход — Page Object. Его особенность заключается в том, что страница представлена в виде модели с которой взаимодействует тест. Это уменьшает количество повторения кода. Доступ к элементам страницы осуществляется только в одном месте. Если поменяется разметка, то потребуется минимум изменений в коде Page Object, а тесты не нужно будет менять вообще.
Таким образом, с точки зрения кода функциональные тесты превращаются в тестирование сервиса, который знает всё о внутреннем устройстве всей страницы или её части и реализует публичные методы, выполняющие определённые действия.
Смотрите пример — https://gist.github.com/mistakster/597f110631fe8a5cde6b. Инфраструктура для запуска этого теста описана в заметке Node.js + mocha + selenium-webdriver.
Я тестирую главную страницу Яндекса. Она должна удовлетворять следующей спецификации:
Yandex home page
√ should be valid (4857ms)
√ should have at least 9 tabs above the search (4358ms)
√ should have a weather widget (1562ms)
Сам тест выглядит очень просто и понятно. Вся магия скрыта в объекте Page
и двух компонентах, которые должны быть на странице.
Когда мы открываем страницу, то не должны знать её адреса. Для разных окружений (локальная разработка, стейджинг, продакшин) он может быть разным. В тесте у Page Object просто вызывается соответствующий метод
open()
. Мы так же должны быть уверены, что страница открылась и на ней правильное содержимое. За это отвечает метод validate()
. Итак, всю логику по взаимодействию с драйвером мы прячем в Page Object за компактным фасадом из методов.
Методы Page Object должны возвращать объекты других страниц или объекты компонент. Так осуществляются переход между страницами или в тесте можно получить доступ к отдельным блокам на странице. Например, в тесте можно получить список всех пунктов меню, которое расположено над поисковой строкой, или текущую погоду в вашем городе.
Коментарии к заметке
Не не не. Если в коде поменялись классы — это не должно волновать функциональный тест. Функциональный тест пытается взаимодействовать жеж как польвазотель, а пользователь видит названия классов? Нет. В Фнукциональном тесте написано «Нажимаю на кнопку „Сохранить“» — тогда он ищет кнопку с текстом сохранить, а не классом
.btn-save
Да, но это же можно сделать реиспользованием части сценариев — сниппетами. Разве только, что это дольше по времени.
Евгений, ты совсем не подумал о локализации сайта или возможности менять текст через админку. С таким подходом ты ещё больше чудес нахватаешься. Я боюсь, что тебе понадобится ещё указывать какой-то контекст, т.к. кнопок «Сохранить» может быть очень много на странице.
Если не нравится привязываться к оформительским классам, заведи классы для тестирования. Классы хороши тем, что дают удобную абстракцию над разметкой. Уже не важно как свёрстана кнопка — через тег
<button>
или<span role="button">
.Сейчас мы делаем проекты на React.js и нам вообще не нужны классы, чтобы навешивать события или искать DOM-элементы. Остаются только оформительские классы, которые, чаще всего, общие для всех элементов управления. Тестеры не могут различить элементы и просят нас специально добавлять какие-либо классы элементам.