+ более качественная, но менее смешная версия обложки
Рано или поздно все приходят к АТ. Ситуация, когда это происходит поздно, понятна, а когда рано? И как понять, что уже можно?
Статья основана на опыте одной команды: расскажу про наши предпосылки и поводы внедрения автотестирования, какие мы выделили критерии готовности к АТ и какие инструменты используем в итоге. Спойлер: в конце немного успешных и не очень кейсов с Xamarin.UITest.
Вводная про продукт
Наша команда разрабатывает мобильные приложения для систем документооборота. Они умеют создавать, редактировать, подписывать, искать документы, отправлять и принимать задачи, работать с карточками документов и разными записями справочников. Поддерживают работу offline.
Взаимодействие приложения с СЭД происходит через веб-сервис.
Взаимодействие приложения с СЭД происходит через веб-сервис.
Что говорит теория
Рассмотрим подход к автоматизации на примере пирамиды тестов. В качестве уровней пирамиды я возьму те виды тестирования, которые применяем мы. А именно unit-тесты, интеграционные тесты и сквозные (E2E) тесты.
Модульные тесты (unit тесты) проверяют работу отдельных мелких частей системы (функцию, метод). Они небольшие, быстро проходят, не требуют больших затрат на разработку и поддержку.
Интеграционные тесты проверяют работу приложения с внешними компонентами. Например, с БД или различными сервисами. Они отнимают больше времени, как на написание и поддержку тестов, так и на их прогоны. Для таких тестов чаще всего требуется настройка и поддержка какого-то окружения. В этом случае они часто становятся и более хрупкими, т.к. окружению свойственно ломаться.
Сквозные тесты проверяют работу системы в целом, эмулируя действия конечного пользователя. Чаще всего они обращаются к системе через UI: жмут кнопки как пользователь, заполняют поля и т.п. Но могут быть применены и в системах без интерфейса. Эти тесты обходятся значительно дороже, чем рассмотренные выше, т.к. требуют больше времени на разработку и поддержку как самих тестов, так и всего окружения. К тому же они очень хрупкие, потому что на них влияют изменения в любой части системы, а на результат конкретного теста может повлиять неожиданное поведение эмулятора или браузера. Длительность прогона таких тестов тоже значительно выше, чем у остальных: для выполнения какого-то отдельного действия пользователя, необходимо совершить много дополнительных. Например, залогиниться или перейти в нужный пункт меню.
По принципу пирамиды, чем легче, быстрее и дешевле тест, тем больше их должно быть в процентом соотношении от общего количества тестов. Т.е. сквозным тестом не стоит проверять присвоение различных значений одному полю (если только вам не нужно проверить работу UI в этих случаях).
Для всех перечисленных видов тестирования отведена определенная роль. В какой-то момент ЖЦ приложения появляется необходимость в той или иной автоматизации тестирования. Ваш продукт легко может обходиться только модульными тестами, а может быстро дорасти до необходимости применения сквозного тестирования. Главное при планировании автоматизации — понимать, что конкретно вашему продукту в текущий момент принесет пользу, а на что вы, скорее всего, зря потратите время.
При внедрении автоматизации не стоит забывать про ручное тестирование, даже при большом объеме автоматизации, всегда будут оставаться вещи, которые необходимо проверять вручную. Как минимум, новая функциональность, для которой не рационально сразу писать тесты.
Но вся автоматизация, на мой взгляд, в первую очередь должна быть направлена на снижение объема ручного тестирования. А при планировании ручного тестирования стоит учитывать, какие кейсы уже автоматизированы.
Как организованы автотесты у нас
Модульные тесты есть у каждого продукта в отдельности, запускаются на каждом PR. Они находятся в ответственности разработчиков.
Интеграционные тесты проверяют взаимодействие веб-сервиса с СЭД.
Они имитируют работу клиентского приложения. Обращаются к методам веб-сервиса для получения и изменения данных СЭД.
Запускаются после каждой сборки новой версии серверной части.
Сквозные тесты имитируют работу конечного пользователя. Жмут на кнопки в интерфейсе мобильного приложения, а приложение работает с СЭД через веб-сервис.
Интеграционными и сквозными тестами сейчас занимаются тестировщики.
Зачем же нам нужны были сквозные АТ мобильных приложений?
Прежде чем приступать к автоматизации, стоит подумать о том, какую проблему вы хотите решить ее внедрением. Если у вас нет конкретных целей, вы не сможете объяснить руководителю или product owner-у, зачем тратить время на автотесты. Сложно будет и оценить пользу их внедрения.
Мы долго тестировали мобильные приложения вручную. Пока это было приложение с небольшой функциональностью, мы успешно справлялись. Все что разрабатывалось было ± в одной области, и ручное тестирование можно было организовать так, чтобы быстро и с небольшой трудоемкостью проверить все возможности приложения.
Но через какое-то время приложение начало обрастать новыми фичами, которые были довольно самостоятельными и требовали к себе большего внимания. Появилась проблема с багами в старой функциональности, которые мы могли обнаружить только на последних этапах проекта.
Поэтому исходными целями внедрения UI-тестов мобильных приложений для нас были:
- покрытие АТ основных кейсов приложения;
- уменьшение количества багов на регрессии перед релизом.
Достижение первой цели должно было автоматически привести к достижению второй, т.к. регулярные прогоны тестов на основную функциональность в ходе всего проекта должны находить баги на более ранних этапах.
Спустя какое-то время добавилась еще одна цель – уменьшение количества ручных регрессионных тестов.
А когда пора внедрять автоматизацию в тестирование?
Прежде чем приступить к автоматизации тестирования, стоит оценить готовность вашего приложения к автоматизации. А так же и вашу готовность к этому процессу.
Стабильная функциональность
Чтобы у АТ был шанс приносить пользу, приложение должно иметь стабильную функциональность. И именно ее стоит покрывать автотестами. Иначе вы потратите много времени и сил на актуализцию и допиливание тестов в результате изменений приложения.
Планы развития
Автоматизацию стоит внедрять только в том случае, если у вашего приложения есть будущее, планы развития на ближайшие годы. Зачем автотесты приложению, которое не меняется?
Ресурсы
У вас должны быть ресурсы на разработку тестов, а главное – на их дальнейшую поддержку. Т.е. при планировании внедрения автоматизации важно понимать, что ресурсы нужны будут не только на то, чтобы тесты написать. Тесты обязательно будут падать по каким-то причинам. Результаты прогонов необходимо будет анализировать и принимать меры. В т.ч. менять что-то в тестах. Ну и, кроме поддержки, не стоит забывать и о необходимости их развития.
Как решиться?
При мыслях о UI-тестах мобильных приложений нам в голову сразу приходили большие полки с девайсами или фермы, на которых арендуются устройства. Представлялась куча проблем в тестах из-за необходимости проверять разные размеры и разрешения экранов. Да еще и опыта в разработке особо не было. Это все пугало и заставляло отложить планы подальше.
На помощь пришли сформулированные ранее цели, и главной из них была проверка функциональности. Поэтому мы начали с малого.
В итоге наши тесты:
- прогоняются 1 раз в день (этого вполне достаточно, чтобы в случае чего найти источник проблемы);
- запускаются локально на наших серверах;
- на двух девайсах (iOS и Android);
- для Android сейчас около 50 тестов, прогон занимает около часа (вместе со сборкой);
- для iOS – около 40 тестов, прогон занимает около 30 минут;
- тесты написаны с использованием Xamarin.UITest;
- запускаются автоматически билдами в TFS, там же в TFS мы мониторим результаты прогонов.
Немного о Xamarin.UITest
Это фреймворк для автоматического тестирования UI для проектов на Xamarin.iOS и Xamarin.Android (заявлена также поддержка Objective-C / Swift и Java). Тесты пишутся на C#, с использованием NUnit. В проекты приложений встраивается довольное легко.
Принцип работы фреймворка основан на двух составляющих: поиск элемента (Queries) и выполнение с ним каких-либо действий (Actions), например, нажатие или выполнение свайпа.
Вот, к примеру, тест, проверяющий отображение ошибки при вводе неверного логина:
public void ShowErrIncorrectLoginOrPassword_IfLoginIsWrong()
{
var wrongLogin = TestsSettings.UserLogin + "1";
app.EnterLoginAndPassword(wrongLogin, TestsSettings.UserPassword);
app.WaitForElement(Resources.Identifiers.ErrorMessage, "Login is incorrect, alert message wasn't shown.", TestsSettings.Delay);
Assert.AreEqual(CoreResources.ErrIncorrectLoginOrPassword, ErrorMessage);
}
private string ErrorMessage =>
app.Query(x => x.Marked(Resources.Identifiers.ErrorMessage)).First().Text;
Используемый в нем метод ввода учетных данных:
public static void EnterLoginAndPassword(this AndroidApp app, string login, string password)
{
app.WaitForElement(Resources.Identifiers.LoginEdit, TestsSettings.Delay);
app.EnterText(Resources.Identifiers.LoginEdit, login);
app.EnterText(Resources.Identifiers.PasswordEdit, password);
app.Tap(Resources.Identifiers.LoginButton);
}
В этом примере как раз используются стандартные методы фреймворка – ожидание элемента, ввод текста, нажатие на элемент.
При разработке и отладке тестов удобно использовать встроенную консольную утилиту REPL (read-eval-print-loop), которая позволяет посмотреть дерево элементов, расположенных сейчас на экране, а также выполнить стандартные методы фреймворка.
Чтобы было для нас неожиданным
Обращение к элементами интерфейса иногда приводило не к тому что мы ожидали.
Например, когда новое окно в приложении открывается фрагментом в той же активити, пользователь на экране видит только это новое окно. Но в дереве видимых элементов в этом случае будут и те элементы, которые пользователь сейчас не видит глазами. Поиск такого «невидимого» элемента выполнится успешно, и с ним можно будет выполнить действие. Вот только нажатие выполнится именно в том окне, которое видит пользователь. Т.е. фактически это будет ложное срабатывание.
В дереве может оказаться несколько одинаковых элементов, по умолчанию действие выполнится с первым подходящим элементом дерева. И если вы в тесте обращались к элементу по лэйблу, а потом у вас где-то появится элемент с таким же лейблом – тест начнет падать (а может и нет, если нужный вам элемент будет первым).
У нас был один случай, когда написанный и отлаженный тест упал при первом же боевом запуске. Потому что тесты запускались на устройстве с другим размером экрана. И элемент, на который осуществлялось нажатие, на этом устройстве оказался под другим элементом интерфейса.
Папка Outbox оказалась под кнопкой Create Task, и нажатие на папку в данном случае приводило к нажатию на кнопку. Для пользователя это привычная ситуация, он просто проскроллит экран. А вот в дереве элементов этого наложения не видно.
Подобные проблемы доставляют незначительные неудобства и заставляют тщательнее продумывать некоторые тесты. А иногда мы просто подгоняем данные в базе так, чтобы тесту ничего не мешало. Ведь цель в данном примере – открыть папку, а не проверить что ее открытию ничего не мешает.
Еще одной неожиданностью и разочарованием стала невозможность запускать и отлаживать тесты для iOS из Visual Studio for Windows. Эта возможность пока не реализована. Приходится работать в студии для MacOS.
Немного капитанских итогов
Внедряйте автоматизацию, если в ней есть смысл.
Пусть ваши тесты будут с минимумом конфигураций, пусть запускаются вручную и только раз в месяц, но если они решают ваши проблемы и помогают вам – почему нет?
Ну и не забывайте про принцип пирамиды.
ThunderCat
a_amkd Автор
сделано. Спасибо