Нужно прокликать 100500 страниц и проверить весь функционал… И перед следующим релизом еще раз проверить то же самое… И еще… И завтра опять. В какой то момент проверка начинает занимать больше времени, чем разработка нового функционала. «А как же е2е-тесты?» — спросите вы. Но, во-первых, их еще нужно написать. А во-вторых, перед тем как начать их писать, нужно написать тест-кейсы. Очень много тест-кейсов.
Если при чтении этих строк ваш лоб покрылся испариной, не переживайте. В этой статье я поделюсь с вами идеей, как мы в Tinkoff автоматизировали тестирование одного из веб-приложений, не написав при этом ни одного тест-кейса и е2е-теста.
Автоматическое написание тест-кейсов
Так уж вышло, что тестирование нашего веб-приложения в основном связано с проверками интерфейса. Нужно проверить, что на экране присутствует кнопка, нужный заголовок и текст, а при вводе невалидного значения в input появляется сообщение об ошибке.
Соответственно, при написании тест-кейса нужно записывать все действия:
- «Нажали кнопку»
- «Ввели значение ХХХ»
- «Выбрали значение YYY в выпадающем списке»
и проверки:
- «Появился текст: ХХХ»
- «Появилось сообщение об ошибке: YYY»
- «Появился заголовок: ZZZ»
После анализа всего функционала нашего веб-приложения мы выделили около 30 уникальных действий и проверок. Стало понятно, что этот процесс можно автоматизировать. Для этого нужно всего лишь отследить все действия тестировщика на странице и реакцию сайта на эти действия.
Начнем с перехвата событий. Чтобы отследить взаимодействие с такими контролами, как кнопка, переключатель и чек-бокс, нужно подписаться на событие click. В каждом фреймворке для этого существуют свои методы. Например, fromEvent в Angular и document.addEventListener в JavaScript и React. Для элементов управления с возможностью ввода, таких как календарь или инпут, изменится только тип события, на которое нужно подписаться: вместо click будет focusout.
fromEvent(this.elementRef.nativeElement, 'click') .subscribe(tagName => { if (tagName === 'BUTTON') { this.testCaseService.addAction(`Нажать на кнопку "${action.name}"`); } else if (tagName === 'INPUT-CALENDAR') { this.testCaseService .addAction(`Выбрать дату "${action.name}" "${action.value}"`); } });
Ну и, наконец, самое главное — проверки. То, как сайт должен вести себя в ответ на действия тестировщика.
Что обычно проверяет тестировщик? Например, он ввел невалидное значение в input, сайт отреагировал на это сообщением об ошибке. Или, допустим, мы нажали на кнопку и в ответ открылся новый экран, изменился заголовок, появился новый текст, перестроились элементы управления. Все эти изменения связаны с изменением в DOM-дереве. Есть много вариантов отследить их. Можно, например, использовать MutationObserver в React и JavaScript или ngAfterViewInit в Angular (проставляя директиву на интересующие элементы формы на сайте).
ngAfterViewInit() { const tagName = this.nativeElement.nodeName; const text = this.nativeElement.textContent; if (['SPAN', 'P'].includes(tagName)) { this.testCaseService.addContent(`**Появился текст** "${text}"\n`); } else if (tagName === 'H1') { this.testCaseService.addContent(`**Появился заголовок** "${text}"\n`); } … }
Код будет очень сильно зависеть от верстки. Посмотрим на разметку. Эти кнопки взяты из «Гугл-переводчика».
<div class="tlid-input-button input-button header-button tlid-input-button-text text-icon" role="tab" tabindex="-1"> <div class="text">Текст</div> </div> <div class="tlid-input-button input-button header-button tlid-input-button-docs documents-icon" role="tab" tabindex="-1"> <div class="text">Документы</div> </div>
Несмотря на то что кнопки не представлены в виде тэгов button, присмотревшись к разметке, по css-классу “input-button” можно выделить все кнопки на странице, а по вложенному css-классу “text” можно достать названия кнопок.
Полдела сделано, осталось только записать все, что мы отследили, в тест-кейс.
Мы включаем перехват всех действий на сайте по определенному сочетанию клавиш и только на тестовом контуре. Остановку перехвата всех событий на сайте осуществляем тоже по определенному сочетанию клавиш. Это позволяет начать и остановить автоматическую запись тест-кейса с любого места.
Автоматическое написание е2е-тестов
Если посмотреть на автоматически сгенерированный тест-кейс, то это по сути пользовательские сценарии, приведенные к одному виду. А значит, их можно сконвертировать в е2е-тесты. Можно даже сразу писать е2е-тесты после перехвата всех действий и проверок, минуя тест-кейсы.
Сейчас существует большое количество различных фреймворков с gherkin-нотацией, основанных на поведенческих сценариях: SpecFlow, xBehave.net., Cucumber.js, CodeceptJS и т. д.
Чтобы получить features из тест-кейса, нужно добавить перед действиями ключевую фразу When и перед всеми проверками Then и And.
Получим автоматически сгенерированный е2е-тест:
Feature: Автоматически сгенерированный е2е-тест Background: When Авторизуемся "логин" "пароль" Scenario: When Нажать на кнопку "Ответил кто-то другой" Then Переход на экран "Кем приходится клиенту" And Появился заголовок "Ответил кто-то другой" When Выбрать в поле "Кем приходится клиенту" "Родственник" When Выбрать в поле "Уточнение" "Супруг или супруга" When Нажать на кнопку "Продолжить"
Чтобы прогон тестов заработал, сгенерированных features мало — нужно написать обработчик для всех действий и проверок.
Есть хорошая новость: писать обработчик для каждой фичи не нужно. Как я уже говорила, несмотря на большое количество различных форм на сайте, у нас получилось всего 30 уникальных действий и проверок, а значит, ровно столько же будет и методов в общем обработчике для всех е2е-тестов. Код будет немного отличаться — в зависимости от выбранного фреймворка с gherkin-нотацией и верстки на сайте. Но написание самого обработчика не займет много времени.
When('Нажать на кнопку {string}', async function (button: string) { const xpath = "//button"; const btn = await getItemByText(xpath, button); await waitAndClick(btn); }); When('Выбрать дату {string} {string}', async function (label: string, text: string) { const xpath = "//*[contains(text(),'" + label + "')]/ancestor::outline"; await inputSendKeys(currentBrowser().element(by.xpath(xpath)), text); });
Теперь, проверяя очередную задачу, за тестировщика автоматически пишется тест-кейс и прогоняется автоматически сгенерированный е2е-тест.
Если кратко, вам нужно:
- Подписаться на события взаимодействия с элементами управления и реакцию сайта на эти действия (через отслеживание перестроения DOM-дерева).
- Конвертировать данные из п. 1 в е2е-тесты.
- Написать общий обработчик для прогона е2е-тестов.
Этот подход поможет вам уйти от рутины. Вы сможете автоматизировать написание тест-кейсов и е2е-тестов для простых проверок, связанных с интерфейсом. Мы же пошли еще дальше и проверяем автоматически также запись в БД и отправку в сторонние сервисы.
Об этом, а также о версионировании, стеке технологий и даже о проблемах на первом этапе внедрения и их решении я рассказывала на конференции Heisenbug-2019 в Москве.
В этой статье я постаралась передать основную идею, не вдаваясь в подробности.
Заключение
Сейчас на написание тест-кейса и е2е-теста у нас уходит в среднем 2 минуты — это в 60 раз быстрее первоначальных подсчетов, когда мы хотели писать тест-кейсы и е2е-тесты вручную.
Мы не меняли процессы в команде. Больше не нужно было выделять емкость тестирования на написание тест-кейсов и брать в команду автоматизатора.
Мы полностью ушли от понятия регресса. Если раньше, при двухнедельном спринте, регресс у нас занимал больше 3 дней, то сейчас регресс занимает время на прогон всех е2е-тестов, а это всего 2 часа.
При ручном написании е2е-тестов очень сложно идти параллельно с тестированием. Теперь же е2е-тесты пишутся автоматически во время тестирования задачи, и тестировщику не нужно проверять один и тот же функционал дважды.
В результате наша команда, не меняя состав, стала работать намного эффективнее.
ссылка на оригинал статьи https://habr.com/ru/company/tinkoff/blog/499476/

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