От объема задач и проблем устаешь так, что даже отпуск не помогает. Люди даже увольняются из-за автотестов.
Боль, страдания и мучения неизбежно приводят к появлению чего-то нового и прекрасного. Мы постарались собрать вместе все грабли, на которые нам пришлось наступить, объединили свои усилия с ребятами из «Авито» и HH и создали то, что сделает ваши отношения с автотестами несравнимо лучше и плодотворнее.
Встречайте: Kaspresso — фреймворк для автотестирования, который вы ждали!
Я сразу отмечу, что в сети доступны два довольно качественных видео, посвященных Kaspresso и AdbServer (вспомогательный для Kaspresso, но в то же время, сильный и независимый проект):
1. Дмитрий Мовчан, Евгений Мацюк — Как начать писать автотесты и не сойти с ума
2. Егор Курников — Единственное, что вам нужно для UI-тестирования
В них подробно описывается история создания библиотек: как мы продвигались от решения одной проблемы к решению другой, и что в итоге получилось. Крайне рекомендую.
Поэтому в статье я расскажу только про основные положения и фишки, чтобы вы быстро могли понять, про что вообще этот фреймворк и какие задачи он решает. А кишки и подробности можно найти в видео и документации.
А зачем нам вообще свой фреймворк?
Каждый разработчик, приступающий к написанию автотестов, неизбежно задается вопросами:
- Как начать писать автотесты?
- Какие инструменты выбрать?
- Что делать, если нужного инструмента нет?
- Какие есть лучшие практики?
Ко всему этому прибавьте то, что каждая команда пытается решить эти вопросы как-то по-своему. В результате единого ответа на них нет, негде подсмотреть, как правильно. Поэтому написание и поддержка автотестов обходятся компаниям дорого, что ставит под вопрос целесообразность автоматизации как таковой.
Между тем автоматизация тестирования преследует благие цели. Она позволяет вам иметь всегда зеленый и готовый к релизу мастер. А это значит, что можно выкатить релиз быстро.
Проблема только в поиске ответов на вышеобозначенные вопросы. А ведь они практически одинаковы для всех команд. Так почему бы не автоматизировать их решение?
Что мы хотим от фреймворка?
Давайте немного раскроем наши ожидания от фреймворка.
Хорошая читаемость
По умолчанию в Android нам доступна только библиотека Espresso. Есть еще, конечно, Appium + Cucumber, которые в теории позволяют писать тесты сразу на две платформы. Но комьюнити уверенно движется в сторону именно первого инструмента. Я не буду описывать все «за» и «против» вышеупомянутых библиотек: в сети полно информации об этом. Вот, например, одна из относительно последних ссылок: Appium vs Espresso. Что выбрать и как использовать?
Так вот, Espresso. Неплохой инструмент, но api у него немного вывернутый наизнанку. Взгляните на простенький код:
@Test
fun espressoTest() {
onView(allOf(allOf(withId(R.id.espresso),
isDescendantOfA(withId(R.id.coffee_variates))),
isDescendantOfA(withId(R.id.content))))
.check(matches(withEffectiveVisibility(View.VISIBLE)))
}
Приходится подумать, чтобы разобраться, не так ли?
Боги из Таиланда и Австралии подарили нам библиотеку Kakao, с которой можно с первого взгляда понять, что происходит в вашем тесте. Вот тот же код, но с Kakao:
@Test
fun kakaoTest() {
mainScreen {
myView.isVisible()
}
}
Гораздо лучше. Но теперь представьте, что вы автоматизировали целый тест-кейс. Каким примерно будет код?
@RunWith(AndroidJUnit4::class)
class OpenHomeScreenTest: TestCase() {
@Test
fun test() {
MainScreen() {
homeButton.click()
}
HomeScreen() {
title {
isVisible()
hasAnyText()
}
}
}
}
Главная проблема заключается в том, что, глядя на этот тест, трудно соотнести его с тем тест-кейсом, который вы автоматизировали. Можно, конечно, добавлять логи или что-то в этом роде. Или ввести dsl, которая сразу преобразит внешний вид ваших тестов:
@RunWith(AndroidJUnit4::class)
class OpenHomeScreenTest: TestCase() {
@Test
fun test() {
step(“1. Open Home screen”) {
MainScreen() {
homeButton.click()
}
}
step(“2. Check Home title”) {
HomeScreen() {
title {
isVisible()
hasAnyText()
}
}
}
}
}
Согласитесь, совсем по-другому выглядит.
Стабильность
Любая библиотека для ui-тестов «флэкает». Одно и то же действие может выполниться 50 раз успешно, а на 51-м сломаться по непонятной причине. А на 52-м прогоне снова все хорошо. И такие «флэканья» могут прилично подпортить вам нервы.
Мы подумали, почему бы не попробовать перехватывать все действия Kakao-Espresso, и уже туда добавлять дополнительное поведение, направленное на обработку таких вот случайных ошибок.
Именно так и появилась на свет версия 2.1 библиотеки Kakao, позволяющая встраиваться во все вызовы Espresso.
Дополнительно мы создали свои интерсепторы, с помощью которых можно менять поведение в точке вызова или, например, просто логировать. Причем эти интерсепторы — настраиваемые, так что вы можете подстроить их под свои нужды. Подробнее лучше прочитать в доке.
Конкретно в рамках борьбы с flaky-тестами — если какое-то ваше действие выдало исключение, то Kaspresso попробует:
- Доскроллить. Может, ваша вьюшка просто не видна на экране.
- Убрать системный диалог, который мог взяться бог знает откуда.
- Повторить сломавшийся вызов в течение двух секунд.
Этими действиями мы полностью решаем вопрос с flaky-тестами!
Логирование
Одна из главных проблем, которая сопровождает автотесты, — это отсутствие внятного логирования, которого особенно не хватает, когда тест падает. Сиди и гадай, что и как здесь упало.
Благодаря вышеупомянутому интерсептингу мы смогли построить довольно обширную систему логирования.
Давайте взглянем на пример:
По-умолчанию Kaspresso логирует все ваши действия, выделяет каждый шаг теста, выводит время выполнения и т.д.
Полноценный Adb в Espresso-тестах
Изначально adb недоступен в Espresso-тестах. Да, есть adb shell, но там гораздо меньше функций, чем в полном adb. А ведь в нем столько всего, что может нам пригодиться в тестах.
Мы создали отдельную библиотеку AdbServer, которая вернет в ваши тесты полноценный adb! В вышеприведенных видео подробно рассматривается, как мы боролись и через что прошли ради него (раз и два).
Работа с OS Android
Специфика тестов в «Лаборатории Касперского» такова, что нам проходится много работать именно с OS Android: выставлять какие-то настройки, закидывать файлы в систему и т. д. Все это побудило нас стандартизировать всю нашу работу с системой, создав набор понятных интерфейсов, доступных через единую точку входа — класс Device.
Что это за интерфейсы, и что они делают? Давайте я в качестве иллюстрации приведу пару слайдов из презентации Егора:
Документация — здесь.
Под капотом используются в основном AdbServer и UiAutomator.
Но! Если вас вдруг не устраивает имплементация какого-то интерфейса, вы можете задать свою имплементацию через Конфигуратор.
Скриншотилка для DocLoc (Documentation and Localization)
У всех проектов, где есть локализация, часто возникает потребность сделать скриншоты на разных языках, чтобы отдать переводчику в качестве иллюстраций. Ведь очень сложно сделать корректный перевод, не видя, где и как используется конкретная строчка. Поэтому хочется, чтобы можно было делать скриншоты быстро и сразу на всех языках. В том числе — скриншоты системных диалогов. Также могут понадобиться скриншоты на легаси-экранах, причем без глобальных рефакторингов.
Все это позволяет сделать Kaspresso из коробки. Подробнее — читайте в документации.
Архитектура и лучшие практики
Одной из ключевых задач Kaspresso было создание такой dsl, которая бы вас подталкивала к правильной архитектуре тестов и правильному их написанию.
На этой теме было сломано немало копий, ведь подобных правил вы нигде, к сожалению, не найдете. Максимум, что можно найти — статьи о Page Object.
Поэтому мы не пожалели сил и осветили эти вопросы и в документации, и в видео раз и видео два.
Кроме того Саша Блинов написал отличную статью про Kotlin DSL и элегантные тесты. Описанные в статье dsl предоставляются Kaspresso.
Еще на Mobius мы предложили вариант, как можно ускорить отдачу от автотестов и быстро встроить их в PullRequest, минуя неизбежные проблемы с инфраструктурой. Об этом мы подробнее рассказываем здесь.
Как подключить и настроить Kaspresso, если у вас уже много тестов
Главная прелесть в том, что если у вас уже много тестов, написанных на Kakao, и вы захотели внедрить Kaspresso, то вам не нужно ничего переписывать! Просто отнаследуйте ваши классы, в которых описаны тесты, от специального класса TestCase. И все!
Было:
@RunWith(AndroidJUnit4::class)
class OpenHomeScreenTest {
private val mainScreen = MainScreen()
private val homeScreen = HomeScreen()
@get:Rule
val activityTestRule =
ActivityTestRule(MainActivity::class.java, true, false)
@Test
fun test() { ... }
}
Стало:
@RunWith(AndroidJUnit4::class)
class OpenHomeScreenTest : TestCase() {
private val mainScreen = MainScreen()
private val homeScreen = HomeScreen()
@get:Rule
val activityTestRule =
ActivityTestRule(MainActivity::class.java, true, false)
@Test
fun test() { ... }
}
А если вам не нравится наследование, используйте аналогичный класс TestRule.
Как мы уже упоминали, Kaspresso — очень гибкий и настраиваемый фреймворк. Все настройки доступны через одноименный класс Kaspresso.
По умолчанию используется дефолтная настройка. Если вы хотите что-то кастомизировать, то это будет выглядеть примерно вот так:
@RunWith(AndroidJUnit4::class)
class OpenHomeScreenTest : TestCase(
Kaspresso.Builder.default().apply {
viewBehaviorInterceptors.add(MyInterceptor())
flakySafetyParams.timeoutMs = 1_000
}
) {
private val mainScreen = MainScreen()
private val homeScreen = HomeScreen()
@get:Rule
val activityTestRule =
ActivityTestRule(MainActivity::class.java, true, false)
@Test
fun test() { ... }
}
То есть через конструктор TestCase доступен Kaspresso.Builder, где вы и задаете все необходимые вам настройки. Подробно про конфигуратор написано в документации.
Ближайшие планы
В самое ближайшее время мы планируем добавить следующие вещи:
Отображение шагов теста в Allure (привет ребятам из HeadHunter)
Через специальный интерсептор мы подготавливаем данные для Marathon. Это позволяет нам видеть Allure-репорты следующего характера:
Подробности в PR#4
P.S. PR уже в версии 1.0.1, сейчас готовим соответствующий PR в Marathon.
PSS. Есть мысль еще к каждому шагу прикреплять конкретный кусок лога, а к «упавшему» шагу добавлять скриншот.
Тестирование upgrade-сценариев
Зачастую бывает необходимо проверить корректность апгрейдов приложения. Да, часть проверок можно переложить на юнит-тесты. Но нам бы хотелось быть спокойными за все приложение в целом.
К сожалению, на чистом Espresso это сделать невозможно, так как если мы переустановим тестируемую apk, то тест зафейлится. Можно как-то попробовать пойти на хитрость с раннером, но мне тяжело представить, как будут выглядеть такие доработки и насколько они будут стабильны.
Поэтому в Kaspresso мы готовим решение данной проблемы, основанное на UiAutomator. Однако наверху у вас будет торчать вся та же привычная dsl, крайне похожая на Kakao и с такой же поддержкой интерсептинга.
Полезные ссылки
Kaspresso
AdbServer
Чат, в котором мы всегда будем рады вам ответить на все вопросы
Благодарности
Отдельное спасибо всем, кто принимал участие в становлении проекта.
Это было очень трудно, но чертовски круто!
Вместо заключения
Мы верим в то, что Kaspresso и AdbServer сделают вашу жизнь лучше.
Будем рады вашим отзывам, рекомендациям, ишуям и ПулРеквестам!
И не забудьте поставить звездочку, пожалуйста!
P.S. И в самом конце маленький опрос =)
Комментарии (12)
Whatyourname
24.09.2019 12:27Зачем вообще нужен любой сторонний фреймворк при работе с adb? Что там происходит такого, чего я не могу сделать сам, используюя только adb?
xoxol_89 Автор
24.09.2019 12:37-1посмотрите видео, пожалуйста
там раскрывается этот вопросWhatyourname
24.09.2019 12:39+1Ненавижу видео. Можно раскрыть его здесь? Чтобы я мог задавать уточняющие вопросы, чтобы мог использовать поиск, чтобы мог цитировать.
v1sar
24.09.2019 15:57+1Например вы не можешь скачать что-то с компьютера (например, с помощью adb, что было бы логично) находясь внутри Espresso тестов.
Почему? Да потому что во время прогона тестов, ваша тестовая apk понятия не имеет о внешнем мире и вообще не в курсе подключена она к какому-то компьютеру или нет.
Вы не можете менять показания датчиков/сенсоров на эмуляторе — потому что это закрытая вещь, к которой доступ строго через adb/telnet
Именно поэтому пришлось создавать AdbServer.
Ненавижу писать комментарии, тут одно пустословие — лучше взгляните код и поймете что к чему, его скомпилировать можно и посмотреть что он делает. А также подправить если вам покажется что-то не так.Whatyourname
25.09.2019 13:49Я же спросил
Что там происходит такого, чего я не могу сделать сам, используюя только adb?
Всё названное я могу делать, используя только adb. И даже могу пинать через него своё espresso приложение, дёргая нужные прямо сейчас классы.
А ответ мне даётся на какой-то другой вопрос, который я, вроде, не задавал.v1sar
25.09.2019 14:45Здесь какое-то непонимание того, для чего вообще AdbServer создавался. Это не замена adb — это и есть adb, поэтому разумеется вы можете делать все то же самое с помощью adb — поскольку это оно и есть.
Идея была в том, чтобы во время тестов вызывать нужные adb команды непосредственно из самих тестов. Нужно посередине теста файл на устройство скинуть? — дошли в тесте до нужно экрана и скинули.
Обычными средствами из самого теста вы не сможете пользоваться adb
vladshulkevich
24.09.2019 13:25Поставлю в план изучения и освоения на второе место.
scottKey
Супер, спасибо за крутой инструмент!
Мы в Райффайзен Банке как раз планируем на него подсесть. Как раз переводим тесты с Appium на нативные, по этому сложно было проголосовать в первом вопросе опросника)