Привет, Хабр!
Для начала представлюсь: я тестировщик мобильных приложений в компании ATI.SU. Чаще тестирую приложения под Android, но в этом году моя команда ступила на кроссплатформенный путь, используя технологию Flutter. В этой статье расскажу, в чём особенности тестирования приложения на Flutter под iOS и Android и чем оно отличается от тестирования нативного приложения.
Как сэкономить время и на что потом его потратить
Мы выбрали Flutter, так как нам было нужно приложение сразу на две платформы. Оказалось, что можно сэкономить время не только в процессе разработки, но и при тестировании.
Для ускорения тестирования мы придумали стратегию: на каждой из платформ (iOS и Android) тестируем только платформ-специфическую функциональность, а всё остальное тестируем на одной платформе.
Что является платформ-специфическими функциональностями:
разрешения приложения (permissions): доступ к файловой системе, камере, гео- разрешения и т.д;
сервисы приложения;
взаимодействие с web view;
пуш-уведомления.
А также стоит учитывать особенности разных версий одной платформы, как и при нативном тестировании.
Что не является платформ-специфическими функциональностями:
UI и вёрстка: цвета, шрифты, расположение элементов;
работа кнопок;
выполнение сетевых запросов и обработка ответов;
реакция на сетевые ошибки, таймаут и отсутствие сети;
работа с БД, миграции БД;
тосты;
перевороты экрана;
смена часового пояса и даты;
функциональные части приложения (или бизнес-логика).
Про последний пункт добавлю, что может быть функциональность, которая по ТЗ должна отличаться на разных платформах, например:
дополнительные элементы интерфейса, только на iOS/Android;
особенности анимаций;
особенности в цветовой схеме.
Также в ближайшее время мы приступим к покрытию приложения автотестами, которые достаточно будет написать один раз вместо двух по сравнению с тестами для нативных приложений.
Таким образом, кроссплатформенность приложения и подход к его тестированию могут сэкономить немало времени. Но сначала стоит разобраться в технических деталях.
Особенности релизной и дебажной сборки
Для тестирования мы используем и дебажную, и релизную версии. Дебаг-версия в первую очередь нужна нам для проксирования, сбора логов в случае ошибок, проверки основной бизнес-логики. На релизной версии мы проверяем анимации, переходы между экранами, скорость отрисовки элементов, производительность и запуск, если в дебажной версии заметили баги. Непосредственно перед релизом проводим тестирование на релизной сборке.
В отличие от нативных приложений, у Flutter-приложения производительность дебажной сборки существенно ниже, чем у релизной. Это может приводить к более медленному отклику и «подвисаниям». Причина такой разницы кроется в виртуальной машине (Dart VM) и JIT (just in time) компиляторе, которые используются для дебаг-версий. (Dart — это язык, который используют для написания Flutter приложений).
Проксирование
Обычно при тестировании нативного приложения для проксирования нужно:
открыть сниффер на компьютере (опустим подробности его настройки);
в настройках девайса задать прокси-сервер для wifi-сети, указав ip-адрес и порт компьютера с включенным сниффером;
скачать и установить на девайсе сертификат сниффера.
В Flutter-приложении такой способ не сработает, потому что http client, встроенный в dart, и популярный клиент dio не используют настройки proxy-сервера, установленные на девайсе. У этих клиентов настройки изолированы от платформ, поэтому настройки проксирования можно реализовать только внутри приложения. Для удобства тестирования разработчики сделали QA-экран, на котором можно прописать адрес и порт.
QA-экран
QA-экран — это внутренняя функциональность, доступная только в дебаг-версии приложения. Она используется для технических настроек приложения, полезных для тестирования: прокси, включение-отключение фичей и дебаг опций, настройка фичей, а также сбор логов для дальнейшего прикрепления их к задаче или баг-репорту.
Приведу несколько примеров использования QA-экрана для тестирования бизнес-логики.
1. У вас есть экран с пагинацией данных. Чтобы протестировать все кейсы пагинации быстрее, очень удобно конфигурировать limit-offset свойства на этом экране. То есть, на экране существует настройка, ограничивающая количество элементов в пачке пагинации.
2. У вас есть скрытые фичи, открываемые при конфигурации фича-флагов. Обычно такие флаги лежат в Firebase или другом ремоут-конфиге. Чтобы не зависеть от настроек ремоут-конфига, удобнее изменять эти опции внутри приложения.
3.В вашем приложении есть какой-то бэкграунд сервис. Можно управлять жизненным циклом сервиса через QA-экран для эмулирования его поведения.
Из-за кроссплатформенности Flutter не поддерживает некоторые привычные Android-тестировщикам опции. Например, UI-опции в настройках разработчика. Давайте посмотрим на эту проблему подробнее.
Тестирование UI-элементов
Как известно, на платформе Android в настройках разработчика есть опции, важные для тестирования UI. Обнаружилось, что некоторые опции для тестирования UI не работают в Flutter-приложении. Например, «показывать границы объектов».
Такое поведение вызвано тем, что Flutter использует собственную систему рендеринга, основанную на графической библиотеке skia. Для операционной системы (как IOS, так и Android) экран Flutter-приложения — это просто окно рендер-системы, в котором происходит прорисовка элементов, поэтому она не может выделить границы.
Чтобы тестировать UI, разработчики добавили на QA-экран дебаг-опции.
Опишу некоторые дебаг-опции, которыми мы пользовались:
checkerboardRasterCacheImages — проверить, какие картинки кешируются;
debugShowMaterialGrid — нарисовать сетку;
debugPaintPointersEnabled — кнопки мигают во время нажатия;
debugPaintSizeEnabled — для каждого объекта отрисовки добавить видимые границы, отобразить отступы и направление выравнивания, а также направления скролла для элементов, поддерживающих скролл;
debugPaintLayerBordersEnabled — отобразить границы каждого слоя отрисовки;
debugRepaintRainbowEnabled — отобразить границы каждого слоя отрисовки, при повышении частоты отрисовок границы элементов окрашиваются в разные цвета;
debugRepaintTextRainbowEnabled — аналогично debugRepaintRainbowEnabled пометить цветовым индикатором элементы, которые регулярно переписываются, но относятся к текстовым элементам;
showPerformanceOverlay — отобразить график времени построения и отображения кадра.
Более подробно о различных дебаг-опциях для UI написано в этой статье.
Тестирование стилей
В разработке приложения отдельной болью является перенос дизайна с макетов. Для решения этой проблемы мы использовали популярное решение: токенизацию системы стилей в приложении. Мы сформулировали отдельные токен-системы для текстов и для цветов.
Для упрощения тестирования токенов мы сделали два отдельных экрана, на которых можно визуально сравнить запланированные дизайнерами токены в Figma и их реализацию в приложении.
Как известно, в iOS есть два варианта стилей для текста: text и display. Для стиля text расстояние между символами больше, чем для display. При автоматическом переносе стилей, весь текст в iOS был в стиле text. Однако не везде в приложении нам это подходило, поэтому для тестирования стилей разработчики добавили таблицу стилей в дебаг-версию приложения. С помощью этой таблицы мы провели дизайн-ревью и решили изменить стили текста некоторых элементов для iOS-версии. Также в дебаг-сборку приложения мы добавили таблицу цветовых токенов, чтобы быть уверенными, что цвета в приложении соответствуют цветам на макетах.
Про стили поговорили, теперь давайте рассмотрим инструменты разработчика, которые есть во Flutter-приложении — Flutter Dev Tools.
Flutter Dev Tools
Flutter Dev Tools — это мощный инструмент для отладки и тестирования Flutter-приложения. В нём есть множество полезных опций как для тестировщика, так и для разработчика: монитор производительности, использование памяти, сниффер, логи.
Чтобы попасть в инструмент, необходимо:
установить плагин Flutter в Android Studio;
запустить Flutter приложение из Android Studio;
открыть Flutter Dev Tools.
В браузере откроется страница Flutter Dev Tools.
А теперь немного подробнее расскажу про функции Dev Tools, полезные тестировщику.
Perfomance. Здесь можно отслеживать производительность приложения в FPS (frames per second). По вертикальной шкале указано время отрисовки кадра в миллисекундах. Если пиковые значения превышают 16 ms, стоит задуматься о том, чтобы пофиксить такое поведение. За производительностью имеет смысл наблюдать только на релизной сборке.
Memory. Показывает использование памяти приложением. При появлении пиковых значений может потребоваться фикс от разработчиков, так как у пользователей бывают слабые устройства с небольшим количеством памяти.
Network. Это простой сниффер, но без возможности подмены трафика. Он не требует дополнительных настроек на девайсе или установки сертификатов, а также отлавливает не только http, но и web-socket.
Logging.Тут все просто — это логи. Их можно сортировать по времени, сообщению и типу. Также есть строка поиска.
И напоследок — впечатления
Приложение, написанное на Flutter, сложно отличить от нативного — с точки зрения и пользователя, и ручного тестировщика. Приложение выглядит идентично на iOS и Android, поэтому пользователю не приходится привыкать к особенностям реализации при переезде на другую платформу.
Наше приложение разработано для бизнеса и внутреннего использования, поэтому там нет большого количества анимаций и сложной графики. Оно не проседает в скорости запуска и производительности на релизных сборках. UI отзывчивый, и его также сложно отличить от нативного.
Кроме этого, для тестировщика есть очевидные плюсы: сокращение времени тестирования и знакомство с новой технологией, поэтому общее впечатление от тестирования Flutter-приложения складывается очень позитивное.
P.S. Посмотрите, как переводится слово “flutter”. Возможно, вы удивитесь и тоже упорхнёте в кроссплатформу!