🔥 Важное для QA-специалистов! 🔥
В QaRocks ты найдешь туториалы, задачи и полезные книги, которых нет в открытом доступе. Уже более 15.000 подписчиков – будь среди нас! Заходи к нам в телеграм канал QaRocks
Это часть серии статей “Масштабное тестирование”, где специалисты отрасли делятся своими подходами. В этой статье Кен Йи, старший инженер Netflix, рассказывает, как тестируют приложение на огромном количестве устройств и как стратегия тестирования эволюционировала за 14 лет.
Введение
Подход к тестированию в Netflix всё время развивается, и чтобы понять, куда он движется и почему находится в нынешней точки, важно посмотреть на его историю.
Android версия приложения стартовала 14 лет назад как гибрид — часть на native, часть на webview. Из-за проблем с производительностью и нативным интерфейсом её переделали полностью под native. Сегодня идёт миграция на Jetpack Compose. Исходный проект — это около 1 млн строк Java/Kotlin в более чем 400 модулях плюс один монолитный. Команда около 50 инженеров.
Раньше была отдельная команда SDET (Software Development Engineer in Test) – инженеров по разработке в тестировании, которая писала тесты, работала совместно с разработчиками и продакт менеджерами, чтобы понять, какие функции они разрабатывают, и создавать тест планы для автоматизации тестирования. Они использовали Espresso, UIAutomator, создавали свои фреймворки и внедряли сторонние решения. Разработчики сами писали юнит и Robolectric тесты. Потом команду SDETов расформировали: теперь автоматизацию ведут сами фича-команды, а 2 SDET инженера помогают по мере необходимости. QA инжерены проводят ручной смоук перед сборкой релиза.
Одна из главных сложностей в тестировании стримингового приложения — большое разнообразие устройств. Мы стараемся обеспечить стабильную работу как на бюджетных моделях с ограниченными ресурсами (например, Android Go), так и на премиальных смартфонах. Поддерживаются устройства до Android 7.0, но в ближайшее время решили повысить минимальную версию до Android 9. Сложности возникают с кастомными прошивками и складными смартфонами, часть из них не передаёт данные с сенсора положения экрана. Поэтому проверка на реальных устройствах очень важна.
Современный подход к тестированию
Сегодня ответственность за тестирование лежит на командах, разрабатывающих функциональность. Они полностью ведут свои фичи — от юнит тестов до E2E автоматизации.
В идеале у нас была бы классическая пирамида тестирования: модульные тесты внизу, затем UI тесты и на вершине — интеграционные и дымовые. Но из-за обилия унаследанного кода и зависимости от многообразия физических устройств структура скорее напоминает песочные часы: много модульных тестов и E2E, но узкое место на уровне UI.
Скриншотные тесты пишутся на трёх уровнях: компоненты интерфейса, макеты экранов и полная интеграция на устройстве. Первые два — быстрые и независимые от сети, третий — альтернатива ручному тестированию, особенно при проверке верстки и локализаций.
Фреймворки для модульного тестирования
Юнит тесты в приложении Netflix покрывают бизнес логику, не зависящую от UI и поведения устройства. В старом коде для асинхронных операций всё ещё используется RxJava, но в новых модулях мы перешли на Kotlin Flows и Composables, они проще в понимании и удобнее для тестирования.
Для модульного тестирования мы используем следующие фреймворки:
- Strikt — библиотека для написания проверок в тестах, с лаконичным API, похожим на AssertJ, но разработана специально для Kotlin.
- Turbine — инструмент для тестирования Kotlin Flows. Закрывает пробелы, которых не хватает в стандартных средствах тестирования потоков.
- Mockito — используется для создания моков (заглушек) сложных зависимостей, не относящихся напрямую к текущему модулю, который проверяется.
- Hilt — позволяет создавать подмены в графе внедрения зависимостей при запуске тестов.
- Robolectric — нужен для тестирования логики, которая взаимодействует с Android компонентами, например, Service или Parcelable.
- Фреймворк A/B тестов и фича флагов — даёт возможность включать, отключать или переопределять функции и настройки в тестах, в зависимости от активных фич или A/B экспериментов.
Важный принцип команды не использовать тяжёлые фреймворки без нужды. Простые юнит тесты работают в разы быстрее. Переход от обычных тестов к Hilt или Robolectric увеличивает время выполнения в 10 раз, а тесты на девайсах ещё медленнее. Mockito с inline моками тоже тормозит сборку, поэтому их стараемся избегать. Тесты на устройствах намного медленнее модульных, поэтому их используют только при необходимости. В больших проектах важна скорость, она влияет на эффективность и стабильность релизных циклов.
Как мы боремся с нестабильностью модульных тестов
Юнит тесты блокируют CI-пайплайн, поэтому важно, чтобы они работали стабильно. Обычно тесты начинают сыпаться по двум причинам: из-за остаточного состояния между запусками и асинхронной логики.
Классы модульных тестов на JVM (Java Virtual Machine) создаются один раз, после чего тестовые методы вызываются поочередно. В отличие от них, инструментальные тесты запускаются заново для каждого случая, поэтому экономия времени возможна только на установке APK. Если тест меняет глобальное состояние (например: файл, базу данных или общий класс), это может вызвать сбой следующего теста. Решается через внедрение зависимостей или пересоздание изменённого состояния.
При тестировании асинхронного кода возможны ошибки из-за гонок потоков. Чтобы этого избежать, используют Test Dispatcher (Kotlin) или Test Scheduler (RxJava). Это сделает код менее реалистичным и, возможно, пропустит некоторые тестовые сценарии, но предотвратит падение тестов.
Фреймворки для тестирования скриншотов
Фреймворки для тестирования скриншотов очень важны, так как проверяют именно визуальную часть интерфейса, а не поведение. Благодаря этому они отлично заменяют ручную проверку статичных экранов. Однако анимации всё ещё сложно тестировать этим методом.
Мы используем несколько фреймворков для тестирования скриншотов:
- Paparazzi — для компонентов UI на Compose и макетов экранов. Поскольку нельзя делать сетевые запросы для загрузки изображений, приходится использовать статические ресурсы или загрузчик, который рисует шаблон вместо нужного изображения (мы используем оба подхода).
- Тестирование локализации скриншотов — делает снимки экранов запущенного приложения во всех языковых версиях, чтобы команды UX могли вручную проверить корректность отображения.
- Тестирование скриншотов на устройствах — проверка визуального отображения приложения непосредственно на реальных устройствах.
- Тестирование доступности с помощью Espresso — это тоже своего рода тестирование скриншотов, где проверяются размеры и цвета элементов на соответствие требованиям доступности. Для нас это было непросто, потому что команда UX выбрала стандарт WCAG с минимальным размером касания в 44dp вместо стандартных 48dp, принятых в Android.
Фреймворки для тестирования на устройствах
Наконец, у нас есть тесты на реальных устройствах. Как я упоминал, работают они значительно медленнее, чем тесты, запускаемые на JVM. Но они заменяют ручное тестирование и используются для смоук проверок основной функциональности.
Но из-за внешних зависимостей (бэкенд, сетевая инфраструктура, лабораторное оборудование) тесты на устройствах почти всегда ведут себя непредсказуемо. Даже настроив повторные прогоны, со временем всё равно будут вылезать сбои. Это просто реальность, с которой приходится мириться при работе с такими тестами. Ниже расскажем, как справляемся с этой проблемой.
Для проверки работы приложения на физических устройствах в Netflix используют большой набор инструментов:
- Espresso — основной инструмент UI-тестирования на Android. С его помощью пишется большая часть автотестов на устройствах.
- PageObject — экраны оформлены как PageObject объекты, что упрощает управление тестами и позволяет безболезненно перейти с XML-разметки на Jetpack Compose.
- UIAutomator — используется для небольшой группы смоук тестов, которые прогоняются на финальной сборке (Релиз кандидат), предназначенной для публикации в стор.
- Фреймворк нагрузочного тестирования — замеряет скорость загрузки экранов, чтобы вовремя заметить проблемы производительности.
- Система записи/воспроизведения сетевых запросов — позволяет прогонять заранее записанные ответы от API, чтобы снизить нестабильность тестов, связанных с сетью.
- Фреймворк моков бэкенда — позволяет тесту запросить от сервера заранее заданный ответ. Например, контент на главной странице формируется исключительно рекомендательными алгоритмами, поэтому тест не может заранее предсказать, какие тайтлы отобразятся. Чтобы провести проверку, тест запрашивает от бэкенда конкретные видео в заданных состояниях. Например, “Последняя возможность посмотреть” и конкретные ряды с нужными тайтлами или ряд “Скоро в эфире” с определёнными фильмами.
- Фреймворк для A/B тестов и фича флагов — позволяет включать или отключать определённые функции и состояния приложения прямо из автотеста.
- Фреймворк аналитики — проверяет корректность событий аналитики, возникающих при действиях пользователя. Такие события чаще всего ломаются при изменении экранов, поэтому требуют особого внимания.
PageObject и тестовые шаги
Паттерн проектирования PageObject изначально применялся в веб тестировании, но со временем его начали активно применять в мобильной автоматизации. Его задача — отделить тестовую логику (например, “нажать кнопку Play”) от деталей реализации взаимодействия с UI (например, команды Espresso). Это позволяет тестам быть независимыми от конкретной реализации интерфейса и проще поддерживаться — особенно при переходе с XML на Jetpack Compose. Экран может меняться, но сами тесты при этом остаются прежними.
Дополнительно мы используем структуру «тестовых шагов». Каждый тест разбивается на последовательные действия, после каждого из которых система автоматически делает скриншот. Это формирует понятную визуальную историю прохождения теста. Если шаг не проходит, сразу отображается описание ошибки и сводка, что помогает быстро локализовать и устранить проблему.
Инфраструктура автоматизированного тестирования

Netflix стал одной из первых компаний, создавших собственную лабораторию для тестирования на физических устройствах — ещё до появления сторонних сервисов вроде Firebase Test Lab. Внутренняя инфраструктура компании включает всё необходимое для полноценного тестирования:
- запуск тестов на конкретных типах устройств
- захват видео во время выполнения теста
- создание скриншотов по ходу выполнения тестов
- сбор логов
Есть и уникальные подходы, характерные именно для Netflix:
- Собственная сотовая вышка в лаборатории, позволяющая тестировать работу приложения в условиях Wi-Fi и мобильной сети
- Настройка качества сети — можно эмулировать медленное или нестабильное соединение
- Блокировка автоматических обновлений ОС, чтобы устройство оставалось на заданной версии
- Только «сырые» ADB команды для установки и запуска тестов — инфраструктура создавалась до появления Gradle Managed Devices и Flank
- Запуск набора автотестов в рамках A/B экспериментов
- Тестирование устройств на корректное воспроизведение контента Netflix. Мы проверяем железо и софт, чтобы убедиться, что устройство не дропает кадры при воспроизведении, контент идет без артефактов и зависаний, поддерживаются HDR и необходимые кодеки (H.265, VP9, AV1 и др.). Для партнёров у нас есть программа сертификации – если устройство прошло тесты, оно гарантированно тянет стриминг в заявленном качестве.
Борьба с нестабильностью тестов
Как уже упоминал, нестабильные тесты — одна из главных сложностей в тестировании устройств. Чтобы минимизировать эту проблему, мы разработали инструменты, которые:
- Снижают уровень нестабильности
- Выявляют причины падений
- Уведомляют команды, ответственные за проблемные тесты
Наши решения:
- Автоматическое определение PR, из-за которого начал падать тест, с оповещением авторов.
- Гибкая маркировка тестов (стабильный/нестабильный/отключен), что позволяет временно отключать тесты при проблемах на бэкенде, избегая ложных срабатываний в PR.
- Автоматическая проверка стабильности — система использует свободные мощности устройств, чтобы определить, можно ли перевести тест в статус Stable
- Правила для автоматических действий (повторные запуски, игнорирование временных сбоев, восстановление устройств).

- Детальные отчеты с фильтрацией по производителю устройства, ОС и другим параметрам, что помогает анализировать частоту и причины падений.

- Возможность ручного запуска теста на разных устройствах и версиях ОС для воспроизведения нестабильных сценариев.
Наш CI/CD пайплайн
- PR проверки (быстрые, <30 мин)
- Юнит тесты (включая Paparazzi и Robolectric)
- Статический анализ (lint, ktLint, Detekt)
- Основные UI тесты (≈1000) на упрощённой сборке с базовой защитой
- Критичные смоук тесты на релизной сборке
- Пост мерж (полноценный прогон, <120 мин)
- Все автоматизированные тесты, которые не вошли в PR
- Дополнительные проверки на полностью обфусцированном билде (с полной защитой кода)
- Долгие проверки (ежедневные/еженедельные)
- Стресс тесты (например, “просмотр сезона сериала без вылетов”)
- Тесты на утечки памяти
- Другие ресурсоемкие сценарии
В идеальном мире у нас было бы неограниченное количество ресурсов для тестирования: бесконечные устройства, чтобы гонять все тесты параллельно, и бесконечные серверы, чтобы проверять каждый юнит тест моментально. Тогда мы бы запускали полные прогоны на каждом PR и ловили все баги до мержа.
Но в реальности приходится искать баланс:
Запускаем достаточно тестов в PR, чтобы не пропустить критические баги, но не тормозить разработку. Добавляем дополнительные проверки после мержа, чтобы покрыть больше кейсов. Оптимизируем время выполнения, чтобы команды оставались продуктивными, а пользователи — довольными.
Главное для нас найти баланс между скоростью разработки и качеством продукта. И наш CI/CD пайплайн построен именно по этому принципу.
Оптимизация тестового покрытия
Тестовое покрытие на устройствах всегда требует поиска баланса. При работе с PR мы стремимся к максимальному охвату при минимальном времени выполнения. Для пост мерж и регулярных прогонов временные ограничения уже не так важны.
Основа тестирования – двумерная матрица, включающая проверки на разных версиях ОС и типах устройств, смартфонах и планшетах. Особое внимание уделяем тестированию вёрстки, поскольку проблемы с элементами интерфейса возникают очень часто. Сейчас мы активно работаем над автоматизацией тестирования складных устройств, где сложность добавляет необходимость проверки интерфейсов в разных состояниях – до, во время и после изменения конфигурации устройства.
В рамках PR проверок мы используем так называемую “узкую сетку”, запуская тесты на одной подходящей версии ОС. Для полноценных прогонов после мержа и по расписанию задействуемя “полную сетку” со всеми поддерживаемыми версиями ОС. Такой подход имеет свою обратную сторону: если возникает проблема, специфичная для определённой версии ОС, в PR она может выглядеть как случайный сбой и будет обнаружена только на этапе полного тестирования.
Это осознанный компромисс – мы жертвуем мгновенным выявлением всех возможных проблем ради поддержания скорости разработки, при этом сохраняя высокий уровень качества за счёт многоуровневой системы проверок.
Развитие тестирования в компании
Тестирование никогда не стоит на месте — мы постоянно ищем способы сделать его эффективнее. Сейчас в фокусе три ключевых улучшения:
Во-первых, тестируем эмуляторы для ускорения PR проверок. Это даст быстрый фидбек без потери качества. Во-вторых, переходим с Paparazzi на Roborazzi и теперь сможем проверять не только статичные скриншоты, но и интерактивные сценарии.
Особые надежды возлагаем на модульную систему демо приложений. Она позволит тестировать отдельные фичи без полной сборки, экономя время и ресурсы.
Но главный принцип остаётся неизменным: идеального тестирования не существует. Мы продолжаем искать баланс между скоростью и качеством, пробуя новые подходы и инструменты. В этом суть нашей работы — постоянное движение вперёд.
Перевод статьи «Netflix App Testing At Scale».