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

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

Проблематика: работа с контекстом и зависимостями

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

Однозначно правильного ответа нет. Но эти два идентифицированных теста не должны происходить одновременно и определенно не будут стоить одинаковых затрат (с точки зрения реализации и удобства обслуживания).

На основе пирамиды тестирования, представленной Мартином Фаулером, мы определили собственную пирамиду, состоящую из 5 уровней:

Для каждого уровня мы определили:

  • Цели тестирования: какие компоненты на самом деле тестируются и какова цель тестирования?

  • Объемы тестирования: будут увеличиваться на каждом этапе пирамиды. Будут делать ваши тесты более зависимыми от локальных и внешних зависимостей.

  • Типы тестов: техника реализации тестов

У каждого уровня теста есть свои особенности

В этом разделе мы пройдемся по каждому уровню пирамиды, снизу вверх ????

Модульные тесты (Юнит тесты)

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

Внешние зависимости приложения, такие как REST клиент, должны быть замокированы. Локальные зависимости класса, такие как репозиторий, также должны быть замокированы.

Все современные языки предоставляют фреймворки для модульного тестирования, такие как XCTest для iOS и JUnit для Android. Используете вы TDD (разработку через тестирование) или нет, модульные тесты должны быть частью критерия готовности (Definition of Done). Модульные тесты должны быть написаны во время реализации фичи.

Интеграционные тесты

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

Внешние зависимости приложения, такие как REST клиент, должны быть замокированы. Локальные зависимости внутри тестируемого компонента можно использовать реальные, в зависимости от цели теста. Локальные зависимости вне компонента должны быть замокированы.

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

Тестирование приложения

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

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

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

Реализация часто осуществляется с помощью тестов пользовательского интерфейса (XCUITest, приложение Espressoor или appium для кроссплатформенной стратегии и стратегии черного ящика) или с помощью Snapshot тестов (тесты на основании эталонных скриншотов и из сравнении с актуальным состоянием приложения).

С этого момента и до самого верха пирамиды реализация новых тестовых сценариев требует делегированных задач. Разработка новых тестовых сценариев должна рассматриваться как отдельная активность.

Системные тесты

Мы почти на вершине нашей пирамиды ???? ! С этого момента нам разрешается использовать некоторые внешние зависимости, такие как сервер приложения.

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

Тесты пользовательского интерфейса и модульные тесты, вероятно, являются двумя наиболее часто используемыми методами реализации. Но, учитывая приведенный выше вопрос среды, их будет сложнее настроить и поддерживать, чем тесты на более низких уровнях. Контрактные тесты (Consumer Driven Contract Testing) являются третьим вариантом. Это очень элегантная техника, которая должна быстро обнаруживать любые регрессионные проблемы между интерфейсом (front-end) и сервером (back-end). Более детальную информацию вы можете найти в документации pact.io

Системные интеграционные тесты

Наконец, мы здесь! Мы можем полностью использовать любые зависимости нашего приложения с помощью тестов системной интеграции ????

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

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

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

Что нам дала эта стратегия?

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

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

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

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

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

Комментарии (0)