company_banner

Автоматизация тестирования веб-приложений под ключ, без регистрации и смс

    Часто бывает так, что веб-приложение состоит из большого количества динамически перестраивающихся форм с разным текстом и элементами управления. Тестирование такого приложения превращается в кошмар.

    Нужно прокликать 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е-тест.

    Если кратко, вам нужно:

    1. Подписаться на события взаимодействия с элементами управления и реакцию сайта на эти действия (через отслеживание перестроения DOM-дерева).
    2. Конвертировать данные из п. 1 в е2е-тесты.
    3. Написать общий обработчик для прогона е2е-тестов.

    Этот подход поможет вам уйти от рутины. Вы сможете автоматизировать написание тест-кейсов и е2е-тестов для простых проверок, связанных с интерфейсом. Мы же пошли еще дальше и проверяем автоматически также запись в БД и отправку в сторонние сервисы.

    Об этом, а также о версионировании, стеке технологий и даже о проблемах на первом этапе внедрения и их решении я рассказывала на конференции Heisenbug-2019 в Москве.

    В этой статье я постаралась передать основную идею, не вдаваясь в подробности.

    Заключение


    Сейчас на написание тест-кейса и е2е-теста у нас уходит в среднем 2 минуты — это в 60 раз быстрее первоначальных подсчетов, когда мы хотели писать тест-кейсы и е2е-тесты вручную.

    Мы не меняли процессы в команде. Больше не нужно было выделять емкость тестирования на написание тест-кейсов и брать в команду автоматизатора.

    Мы полностью ушли от понятия регресса. Если раньше, при двухнедельном спринте, регресс у нас занимал больше 3 дней, то сейчас регресс занимает время на прогон всех е2е-тестов, а это всего 2 часа.

    При ручном написании е2е-тестов очень сложно идти параллельно с тестированием. Теперь же е2е-тесты пишутся автоматически во время тестирования задачи, и тестировщику не нужно проверять один и тот же функционал дважды.

    В результате наша команда, не меняя состав, стала работать намного эффективнее.
    Tinkoff.ru
    it’s Tinkoff — просто о сложном

    Комментарии 9

      0

      Как система понимает, что кликнув тестировщик проверяет заголовок, а не, к примеру, цвет кнопки?

        0
        При нажатии на кнопку, в тест-кейс записываются все изменения на сайте, которые мы обрабатываем (в данном примере, будет запись и об изменении цвета кнопки и о появлении заголовка). Если тестировщик посчитает, что какая-то из проверок избыточна в этом кейсе, то он удаляет ее при просмотре тест-кейса. При этом е2е-тест он не трогает, т.к. при прогоне тестов мы «на лету» забираем все тест-кейсы и конвертируем их в е2е-тесты.
          0
          А как вы передаете состояние в случае если тест требует перехода со страницы на страницу? Ну в смысле когда весь DOM перезагружается. И в чем именно вы запускаете тесты?
            0
            Мы отслеживаем только те изменения, которые проверяет на странице тестировщик. Например, нам интересно появление на новой странице всех блоков с текстом, кнопок, заголовков и т.д. Поэтому, когда перезагружается весь DOM, то мы записываем в тест-кейс только нужные нам изменения через xpath-ы. Для запуска тестов мы используем фреймворк CodeceptJS.
        +1
          0
          Как быть с кейсами, которые напрямую привязанны к данным? Еще данные могут менятся динамически.
            0
            На счет динамических данных, например, таких как даты, мы конвертируем их в формат NOW+-сдвиг дней в тест-кейсе, а в е2е-тесте обратно раскрываем эту дату в обычный формат. Я пишу комментарий 11.05.2020, в тест-кейс я запишу «Я пишу комментарий [NOW]». Если вы завтра запустите е2е-тест прочитаете ответ, то увидите «Я пишу комментарий 12.05.2020». Что касается привязки данных, тут нужно рассматривать конкретный случай. Допустим, при записи тест-кейса вы авторизовались под Иваном Ивановичем и перехватили появление текста «Здравствуйте, Иван Иванович», при этом на сайте вы знаете, что Иван Иванович это ИО, тогда в тест-кейс пишите «Здравствуете [ИО пользователя]», по аналогии с динамическими данными.
            0
            спасибо, было бы неплохо посмотреть на пример проекта на github что-то локально посмотреть, есть такая возможность?
              0
              Мы не выкладывали проект на github, т.к. у всех разные подходы и фреймворки, и сложно унифицировать написание тест-кейсов и е2е-тестов под любой проект.

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое