[Перевод] Тестирование UI в JavaScript – наилучшие практики

image

Это руководство по наилучшим практикам в тестировании UI на JavaScript, от разработки через поведение (BDD) до соглашений об именовании и до того, какие именно операции браузер должен выполнять в рамках тестов.

От качества UI (пользовательского интерфейса) зависит, состоится приложение или развалится. Для вас принципиально, какое первое впечатление пользователь получит от приложения, так как второго шанса у вас может и не быть. Поэтому важность тестирования UI при разработке приложений только растёт. В процессе тестирования UI проверяются те аспекты работы программы, с которыми придётся непосредственно иметь дело пользователю. Но какими методами и приёмами нужно пользоваться, чтобы добиться максимальной эффективности тестирования? В этой статье мы поговорим именно о таких инструментах, использовать которые можно прямо с сегодняшнего дня. Начнём.

Если вы автоматизируете тесты UI при помощи тестировочного инструмента, то можете:
• Убедиться, что элементы UI не схлёстываются и не смещены,
• Проверить, нет ли ошибок в правописании, капитализации или пунктуации,
• Гарантировать, что шрифт чёткий и хорошо читается, подобрать цвет и кегль шрифта,
• Проверить выравнивание изображений,
• Убедиться, что в браузере правильно выводятся сообщения об ошибках,
• Проверить положение элементов UI при разных разрешениях экрана.

Но, если эти тесты не автоматические, то такой процесс может быть обременителен. Ручное тестирование — сильный метод, и он бывает эффективен, если в программе предусмотрено не так много элементов UI или находится на ранней стадии разработки. Однако, чем больше фич подхватывается в программу, и чем больше элементов добавляется в UI, тем вероятнее, что ручная верификация станет неуправляемой.

При автоматическом тестировании UI можно прогонять программу через разные тестовые сценарии с разными переменными. Поскольку тесты автоматизированы, их можно прогонять чаще и, соответственно, максимально быстро обнаруживать ошибки. Ещё одна выгода от автоматического тестирования UI — удешевление разработки. При автоматизированном тестировании исключается необходимость в сотрудниках-тестировщиках, что позволит вам сэкономить время и деньги.

Учитесь пользоваться фреймворком BDD


Разработка через поведение (BDD) — это методология, которая поможет программистам, тестировщикам и менеджерам полностью понимать друг друга в рамках софтверного проекта. Такая методология способствует сотрудничеству между членами команды, так, что все одинаково понимают, как именно должна функционировать программа.

BDD особенно полезна при тестировании пользовательского интерфейса, но также применима и при других видах тестирования, в том числе, при модульных и интеграционных тестах. Допустим, вы хотите написать короткий скрипт, который бы проверял, как работает игровое приложение. Рассмотрим следующий гипотетический пример:

Фича: пользователь покупает скин
  Сценарий: на аккаунте достаточное количество монет 
   При условии, что аккаунт соответствует совместимому с покупкой персонажу
 	И на балансе аккаунта не менее 50 монет
 	И уровень аккаунта не менее 5
	То, когда пользователь подтверждает покупку
	Игра должна добавить приобретённый скин к его аккаунту,
 	А баланс на данном аккаунте должен быть уменьшен на 50 монет
 	При этом, скин должен быть автоматически применён к персонажу


Этот пример написан в стиле BDD с применением синтаксиса Gherkin. Что предпочтёт новый сотрудник — прочитать десятки строк кода или такой сценарий разработки через поведение?
Когда пишешь тесты по принципу BDD, ты экономишь время коллег по команде. Если же тебе самому придётся вернуться к работе над этими тестами через несколько месяцев — то и тебе самому будет проще освежить материал в памяти, соответственно, ты и своё время сэкономишь. У BDD есть и ещё одно преимущество — эта стратегия помогает понимать тесты и требования тем, кто разработчиком не является — например, проект-менеджерам.

Не пользуйтесь sleep () для приостановки тестов


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

Чтобы справиться с этой проблемой, можно попробовать сымитировать возможные задержки, реализовав функцию промедления (timeout), чтобы на некоторое время придержать работу скрипта. Но, если будете при этом неосторожны, то можете привнести нестабильность в ваши тесты UI.

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

Также вам нужно ненадолго приостановить выполнение теста, чтобы приложение успело полностью загрузиться. Если вы пользуетесь браузерной системой автоматизации Selenium, в которой применяется язык Java, то там найдётся функция sleep (), позволяющая сделать именно это:

Thread.sleep();


Метод sleep () принимает число, равное количеству миллисекунд, и приостанавливает выполнение потока на указанное число миллисекунд (в большинстве других языков тоже есть подобные функции). Допустим, чтобы загрузиться, вашему приложению требуется в среднем 4 секунды. А вы для верности хотите приостановить тест на 8 секунд. Поэтому вы добавляете в код Thread.sleep (8000);.

Попытка применить в таком качестве метод sleep () — отличный способ обнулить эффективность теста. Почему? Потому что при каждом прогоне вы впустую тратите примерно 4 секунды. Если тест всего один, то это не так много, но с двумя тестами — уже больше, а ведь у вас может быть большой проект, для тестирования UI в котором могут понадобиться сотни (если не тысячи) тестов во множестве браузеров.

Более того, а что, если из-за всех внешних факторов на загрузку вашего приложения требуется более 8 секунд? Ваши тесты провалятся. Поэтому лучше воспользоваться функцией implicitlyWait ().

Неявно ожидая, вы приказываете браузеру выждать некоторое время при поиске элемента. Поэтому, как только этот элемент окажется найден, скрипт выполнится — и время впустую тратиться не будет. А если в указанный период элемент окажется недоступен, система объявит, что тест не пройден. Вот пример:

WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(8));
driver.get("http://exampledomain/index");
WebElement myDynamicElement = driver.findElement(By.id("nav"));


Неявное ожидание позволяет как сэкономить время, так и сократить издержки при тестировании.

Установить соглашение об именованиях для тестовых случаев


Перед тем, как создавать тесты, важнее всего выработать соглашение об именованиях. Каждый тест должен иметь такое название, которое бы ясно и логично доносило, что именно проверяет этот тест. Предусмотрев соглашение об именовании и следуя ему, ваши коллеги могут:
• Быстро подыскивать конкретный тест,
• Сразу же догадываться, что делает конкретный тест — даже если с момента написания теста пройдут месяцы,
• Выявлять, из-за какой операции тест оказывается не пройден; для этого достаточно свериться с названием теста.

Качественное соглашение об именовании значительно упрощает вам чтение и понимание исходного кода, так что вы можете сосредоточиться на решении более важных проблем. Вот пример плохо поименованного теста:

@Test
public void homepageTest () {.....}


Из этого названия о тесте не следует ничего кроме того, что он проверяет домашнюю страницу. Для сравнения:

@Test
public void userShouldSeeHomepageTitleInBoldFont() {.....}


Это название чётко описывает, для чего нужен тест. Теперь, если этот тест не будет пройден, вы сразу поймёте, какую часть приложения вам требуется исправить.

Не полагайтесь на единственный тип тестирования


Попадаются такие разработчики, которые настаивают, что тестированием UI можно не заморачиваться, а для обеспечения качества программы достаточно провести модульные тесты. Есть и такие разработчики, которые тестируют только UI, а другими тестами пренебрегают. Но на самом деле модульное тестирование и тестирование UI — два подхода, только дополняющих друг друга. Как именно?

При модульном тестировании по отдельности проверяется каждый участок исходного кода (так называемый «модуль», «unit»), чтобы гарантировать, что он отвечает требованиям приложения. Благодаря такому качеству, модульные тесты получаются прямолинейными и быстрыми.
Но модульные тесты не дают точного представления о реальной действующей программе. Они лишь проверяют фрагменты исходного кода по отдельности, не учитывая при этом внешних зависимостей. Существуют всевозможные изъяны, необнаружимые при помощи модульных тестов.

Ещё существует интеграционное тестирование, которое надстраивается над модульным, так как позволяет комбинировать модули кода и проверять их в совокупности. Таким образом, выявляются любые дефекты, возникающие при совместном использовании модулей. Но, опять же, при интеграционном тестировании не учитываются взаимодействия пользователя с графическим интерфейсом.

Именно здесь нам и понадобится тестирование UI. Тестирование UI позволяет проверить визуальные элементы приложения, например, изображения и ссылки, а также пользовательские действия — например, щелчки мышью и работу с клавиатурой.
Это, конечно, не означает, что стоит ограничиваться одним только тестированием UI. Модульные и интеграционные тесты принципиальны с точки зрения QA-подхода и должны применяться наряду с тестами UI.

Умейте тестировать браузер в безмониторном режиме.


В предыдущем разделе мы поговорили о важности модульных и интеграционных тестов, а также обсудили, как они дополняют UI-тестирование. Но, если у вас возникнут проблемы с производительностью, то можете попробовать и безмониторное тестирование браузера (headless browser testing).

В обычных браузерах приходится отображать HTML, обрабатывать CSS и загружать медиа-ресурсы, в частности, картинки и видео. Всё это сказывается на скорости вашего скрипта, тестирующего UI. Более того, если параллельно выполнять несколько таких тестов, то они потребляют много памяти.

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

Для этой цели предназначено сразу несколько браузеров, в частности, PhantomJS и HtmlUnit. Но некоторые обычные браузеры, например, Google Chrome и Mozilla Firefox также могут работать в безмониторной среде.

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

Не выполняйте все тесты во всех целевых браузерах


Иногда, если прогнать тесты во множестве браузеров, это никак не повышает надёжности вашего приложения. Приложение тестируется во множестве браузеров выполняется для улучшения совместимости приложения с браузерами. Но не все тесты нужно выполнять сразу во многих браузерах.

Допустим, например, вы хотите посмотреть, как будет работать форма в трёх наиболее востребованных браузерах (Chrome, Safari, Firefox). Вы хотите проверить две вещи: 1) убедиться, что форма правильно отображается в этих браузерах и 2) гарантировать, что форма верно реагирует на нажатие кнопки «Submit» (Отправить) — это пользовательское действие.

Чтобы решить первую задачу, нужно удостовериться, что все поля для ввода, флажки и кнопки отображаются правильно и работают именно так, как должны. Следует ли прогонять все эти тесты сразу в трёх браузерах? Да. Но нужно ли провести каждый тест по сто раз, чтобы убедиться в результате? Нет. Будет более чем достаточно выполнить каждый из тестов по несколько раз, чтобы достоверно узнать, как выполняется соответствующий функционал.

Но вторая цель иная. Проверка отклика формы никак не связана с проверкой совместимости с браузером. Следовательно, этот тест можно провести всего в одном браузере. Если прогонять все тесты во всех целевых браузерах, это вас только запутает, а также съест всю ту экономию, которой вы могли достичь при помощи автоматизации тестов.

Правильно подбирайте инструменты для автоматизации тестирования UI


Итак, вы, наконец, готовы приступить к автоматизированному тестированию UI. Но какой тестировочный инструмент лучше всего подходит для вашего приложения? На рынке есть различные инструменты для этой цели, в том числе, Selenium, Meticulous, Applitools, Percy, Storybook, Chromatic, Cypress, Puppeteer и Playwright.

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

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

Поддерживается ли в этом инструменте тестирования фреймворк BDD? Без BDD некоторые члены команды могут не понимать, что происходит в тестировочном проекте.

Хороший тестировочный инструмент должен удовлетворять всем требованиям, которые вы можете предъявлять к тестированию.

Заключение


Когда речь заходит об обеспечении качества, среди ваших первоочередных задач — обеспечить тестирование ПО. В этой статье было рассказано, как и почему автоматизация процесса тестирования позволяет существенно повысить качество и частоту тестов.

Также мы рассмотрели различные типы тестирования. Надёжная стратегия тестирования не ограничивается одним типом тестов, например, только интеграционными тестами или тестированием UI. Напротив, нужно предусмотреть различные тесты в зависимости от требований, предъявляемых к приложению.

Соблюдение соглашений об именовании при разборе тестовых случаев — это важный аспект, часто упускаемый из виду. Из названия каждого теста должно чётко следовать, что именно он проверяет.

Чаще всего нет необходимости прогонять во всех целевых браузерах все возможные тесты. Это было бы напрасной растратой времени и ресурсов. Напротив, лучше проверьте, какие тесты нужно провести, чтобы убедиться в кроссбраузерной совместимости.

Не пользуйтесь sleep () для приостановки теста. Берите на вооружение неявное ожидание, эта возможность поможет справляться с тестами быстрее.

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

© Habrahabr.ru