Pull to refresh
347.09
TINKOFF
IT’s Tinkoff — просто о сложном

Тестирование From Zero to Hero. Часть 1

Reading time6 min
Views13K

Всем привет! Меня зовут Сергей, я работаю в команде Тинькофф. Сегодня я хочу рассказать, как мы в Тинькофф приходили к классической пирамиде тестирования. 

Рассказ будет в трех частях:

  • Трудности, с которыми нам пришлось столкнуться, и как мы их преодолевали.

  • Конкретные решения по некоторым распространенным кейсам при написании интеграционных тестов.

  • Подход к написанию E2E-тестов (тестов, покрывающих взаимодействие всех систем приложения, включая back-end и пользовательский интерфейс) с использованием паттерна PageObject, пришедшего к нам из мира веб-разработки.

Вместо предисловия

Было время, когда солнце светило ярче, орки были зеленее, а мобильный банк Тинькофф писали восемь человек. Тогда почти все фичи катились без какого-либо тестового покрытия. В лучшем случае основные компоненты бизнес-логики могли быть покрыты Unit-тестами.

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

Этап принятия

Ранее E2E-тесты писали только автоматизаторы, которых было несколько человек. Тестами покрывалась только малая часть основного функционала. Регресс-тестирование начало затягиваться, и выкатывать фичи в прод стало труднее с учетом роста команды. 

Первый шаг, который мы сделали, — передали написание E2E-тестов разработчикам, причем на обязательной основе. Ни одна фича не может перейти в статус Ready если она не покрыта E2E-тестами. Поскольку критерии приемки задачи описывают QA-специалисты, то они и писали тест-кейсы для каждой фичи.

Тест-кейсы

Тест-кейсы — это шаги, по которым QA-специалист проходит во время тестирования фичи. Сюда входят всевозможные проверки пользовательского флоу, реакция приложения на разного рода corner-case-проверки наличия UI-элементов на экране и так далее.

Пример тест кейса
Пример тест кейса

Тут мы столкнулись с несколькими проблемами:

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

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

    Мы имели три кейса, каждый из которых проверял отдельно каждый экран и не проверял пользовательский флоу. 

  • В E2E-тестах мы проверяли кейсы, которые в принципе не должны проверяться на этом уровне пирамиды. Например, факт отправки запроса и его составляющих или роутинг между экранами, который, по сути, спрятан в одной сущности.

По итогу мы получали пирамиду тестирования в виде песочных часов. Мы делали много Unit- и E2E-тестов и практически не писали интеграционных тестов. 

Почему это не круто?

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

Е2Е-тесты хорошо проверяют интеграцию между всеми компонентами приложения, но обходятся они достаточно дорого по следующим причинам: 

  • Тесты запускаются на эмуляторах. Сам тест проходит долго, потому как он имитирует реальные действия пользователя (одна только авторизация длится около 30 секунд на каждом запуске теста).

  • Прогон Е2Е-тестов занимает много времени. Чтобы запускать такие тесты на пул-реквестах, нужно иметь достаточно мощностей. На данном этапе мы не можем этого делать. Это значит, что обратную связь о том, что что-то сломалось, мы получаем значительно позже. Но для нас это одна из приоритетных целей в области тестирования!

  • Из-за того, что прогоны тестов проводятся на CI, иногда достаточно трудно понять, по какой именно причине сломался тест.

  • Е2Е-тесты имеют свойство падать без каких-либо изменений в коде (нестабильность интернета, нестабильность тестового фреймворка, проблемы на реальном устройстве и другие причины), именно поэтому их еще называют flaky tests.

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

Почему так?

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

Для E2E-тестов понятно, что на тестовом окружении должно быть поднято все, а для интеграционного — только часть и не всегда понятно какая. Это приводило к тому, что всем было проще не разбираться и писать E2E тесты. Это негативно сказывалось на времени прогона тестов в целом.

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

Что мы сделали

Командный тренинг

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

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

Пользовательские истории

У нас было много обсуждений с QA, пока мы не пришли к формату тест-кейса, который должен показывать какую-то пользовательскую историю. 

Небольшой пример

У нас есть фича, в которой пользователь заказывает себе справку по счету. Здесь имеется три экрана:

  • Экран списка справок.

  • Экран настроек справки (язык, период и так далее).

  • Экран превью справки.

Как бы это выглядело раньше?

Мы бы проверили Экран списка справок: UI-элементы, отправляемые запросы. После чего аналогичные проверки были бы на другие два экрана. 

Здесь было две проблемы:

  • Можно было покрыть тестами все, и при этом не было гарантии, что пользователь получит ожидаемый результат.

  • Было много запусков тестов на реальном устройстве, которые во многом дублировали себя.

Как это сделано сейчас?

Тест-кейс != Е2Е-тест. 

Есть тест-кейсы, в которых описана пользовательская история. К примеру, есть фича, в которой пользователь может заказать справку. Мы проверяем в тесте, что с точки входа внутрь фичи до конечного результата пользователь не встречает никаких проблем.

Сам тест разделяется на шаги (steps). Обычно шаг — это один экран внутри всего флоу (но бывают и другие ситуации). Мы пишем в description название этого шага, делаем скриншот и все проверки, которые касаются этого шага. 

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

И есть кейсы, в которых проверяется какое-то конкретное действие, например отправка запроса при нажатии на кнопку. Для таких тестов достаточно написать Unit-тест либо интеграционный тест. Такие ошибки мы можем отлавливать на стадии пул-реквестов и исправлять их до того, как они попадут к QA.

Пирамида

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

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

Мы с ребятами начали разбивать монолитные компоненты на фича-модули. Наша задача — вынести компоненты приложения, которыми пользовались все фича-команды (сетевые слои, работа с базами данных, аналитика и другие). 

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

Также мы смогли показать остальным разработчикам примеры, как стоит писать такие тесты. Было подготовлено базовое окружение для написания интеграционных тестов: 

  • Выделили отдельные Аndroid-модули для тестовых компонентов.

  • Подготовили базовые моки (сущности хранения сессий, базы данных и так далее).

  • Написали документацию по основным принципам тестирования с примерами.

Итоги

Мы пришли к осмысленной, правильной пирамиде тестирования.

  • Начали более сбалансированно распределять тесты по слоям.

  • Задали направление для всей команды, написали несколько тестов, которые можно брать за пример и не бояться потратить три дня на написание одного теста (да, поначалу было и такое).

  • Смогли задать направление для архитектурных изменений и упростить написание окружения вокруг тестов. 

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

Tags:
Hubs:
+19
Comments6

Articles

Information

Website
www.tinkoff.ru
Registered
Founded
Employees
over 10,000 employees
Location
Россия