Сквозные тесты находятся на вершине пирамиды тестирования, они должны дать наибольшую уверенность в том, что тестируемая система работает, но в большинстве систем сквозного тестирования, которые мы обнаруживаем мы боремся с «нестабильными» тестами и в конечном итоге не доверяем набору тестов. Мы надеемся, что сможем изменить это с помощью Detox.

Зарождение

Наша история начинается с Wix App - нашего официального нативного приложения для iOS / Android.

  • Он написан с нуля на React Native.
  • Начали работать чуть более 18 месяцев назад (март 2016 г.)

С точки зрения инженерных усилий:

  • Это приложение является совместным усилием компании. В настоящее время оно включает в себя код из 6 различных групп продуктов.
  • В настоящее время 40 разработчиков работают над этим проектом или поддерживают его с помощью инструментов инфраструктуры.
  • Большая часть кода написана на JavaScript.

Имея Google Play и Apple App Store в качестве средств распространения, наши выпуски по сути не являются непрерывным развертыванием. Итак, у нас есть поезд релизов (2 платформы каждую неделю). Но механизм распространения - это не настоящая причина, по которой мы не выпускаем настоящие компакт-диски.

Мы очень полагаемся на ручное тестирование!

  1. В настоящее время полный набор регрессионных тестов QA содержит 300 тестов, выполнение которых занимает 14 человеко-дней, и, поскольку он настолько велик, мы не можем завершить тестирование вовремя для следующего выпуска, поэтому мы тестируем только ~ 70 из них, что также занимает много времени, 3 человеко-дня на одном устройстве.
  2. Фактически, если мы запустим весь пакет на обеих платформах и только по две версии ОС на каждой платформе, у нас получится 56 (2 платформы x 2 версии ОС x 14) человеко-дней для полного регресса.
    Но становится еще хуже.

QA не масштабируется

  1. Набор тестов QA будет постоянно расти, а это означает, что даже если разработка будет продолжаться в том же темпе, QA будет иметь дополнительную работу над каждым выпуском, поэтому нам придется либо нанять больше QA, либо отказаться от некоторых тестов.
  2. Мобильная разработка в Wix растет примерно на 25% в квартал, и темпы роста продолжают расти.

Давайте рассмотрим упрощенный пример: если разработка идет с одинаковым темпом: 2 функции или исправления ошибок в неделю, тогда у QA будет два дополнительных теста каждую неделю, что означает, что на 1-й неделе у них будет 2 теста, а на 7 неделе люкс будет в 7 раз больше.

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

Будущее за автоматическими тестами!

Впрочем, в этом нет ничего нового ...

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

Это пирамида тестирования, поскольку вы уже знаете, почему тесты так важны, и понимаете различные типы тестов, мы сосредоточимся на том, как мы тестируем каждый тип, а не на объяснении, что они из себя представляют.
Давайте разделим E2E на две части: чистую автоматизацию пользовательского интерфейса (то есть без тестирования внешних сервисов) и полную E2E, имитирующую пользователя с реальными данными сервера. Они должны выполняться на устройстве или симуляторе.

Давайте сосредоточимся на мобильной разработке и конкретно на React Native.

Что мы умеем делать?

  • Модульное тестирование
    Бизнес-логика в основном написана на JS, ее легко протестировать на узле с помощью Jest.
    React Native, как и React, использует архитектуру Flux для управления потоком данных приложения. Одна из самых популярных реализаций Flux - это Redux, которую мы используем во всем приложении. Хотя Redux широко популярен, мы никогда не чувствовали себя комфортно с модульным тестированием приложений Redux, поэтому мы разработали методологии и набор тестов для тестирования приложений redux. Для получения дополнительной информации ознакомьтесь с redux-testkit.
    Другой популярной реализацией потока является Mobx, который гораздо менее популярен, чем Redux, и имеет большие возможности тестирования. Мы придумали индивидуальный подход, чтобы упростить жизнь нашим инженерам. R emx можно протестировать довольно легко, модульные тесты могут быть ванильным JavaScript, совершенно не зная о базовой реализации, мы добавим больше информации о Remx в ближайшем будущем.
  • Тестирование компонентов
    Также выполняется на узле, мы полагаемся на Enzyme от Airbnb и используем Enzyme Drivers, чтобы помочь с имитацией.
  • Автоматизация пользовательского интерфейса / От конца до конца
    Но что вы делаете со сквозным тестированием? Эти тесты дают наибольшую уверенность, потому что они в значительной степени представляют собой робота, запускающего ваше приложение на устройстве.
    Поддерживать комплексный набор тестов сложно и не так надежно, как другие. но почему ?

Шаткость

E2E-тесты часто считаются ненадежными на всех платформах, в Интернете, iOS, Android.

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

Ручная синхронизация

Ручная синхронизация используется настолько часто, что мы встраиваем ее в нашу инфраструктуру тестовых фреймворков. Вызовы API заполняются циклами, содержащими sleep() функции.
Это пример, который я взял из выступления Аарона Гринвальда in React Amsterdam , это реальный фрагмент кода, который мы использовали для тестирования нашего приложения React Native в нашей предыдущей среде тестирования.

Насколько ненадежен ненадежный набор тестов?

Чтобы понять, насколько серьезна проблема нестабильности, давайте посчитаем вероятность отказа набора тестов.

q: вероятность провала теста
n: количество тестов

1-q - вероятность успеха.
(1-q) ^ n - это вероятность успеха всего набора.
1- (1-q) ^ n - вероятность неудачного завершения хотя бы одного теста.

Если тест отслаивается в 0,5% случаев:

Вы понимаете, очень ненадежно ...

Прошлый опыт

Итак, это сложный вопрос ... и в прошлом у нас был опыт работы с несколькими фреймворками.

Appium
Наиболее популярное решение, являющееся стандартом де-факто в отрасли. Мы также проверили, что делают другие компании, выпускающие мобильные продукты, в отношении сквозных тестов, и обнаружили, что у многих даже нет автоматизации, а те, у кого она есть, используют Appium. Внутреннее устройство Appium, его драйвера, реализовано с использованием инструментов (iOS) и UIAutomator (Android), которые по сути являются внешними способами взаимодействия с устройством, как и пользователь.

Мы использовали Appium в течение 2 лет в целом и 8 месяцев с React Native и обнаружили, что потратили неразумную часть нашего времени на написание тестов и ласки системы, чем на написание функций.

Мы обнаружили, что сквозное тестирование действительно сложно:

Тесты нестабильные, мы получали разные результаты на разных машинах, частые сбои в CI, единственным решением для которых было добавление спящих режимов, что замедляло тесты.

Тесты уже были медленными, поскольку инструмент Apple UIAutomation ограничен выполнением одного действия в секунду, и есть хак, который снимает это ограничение Инструменты без задержек (которое уже не поддерживается), поэтому после каждого выпуска нового Xcode нам придется дождаться патча перед обновлением.

Magneto
Также стоит отметить Magneto, среду тестирования E2E только для Android,
решение от Everything.me, где я ранее работал, построен с использованием UIAutomator в качестве основного драйвера.

  1. Он был намного стабильнее, но мы все еще не могли избавиться от нестабильности.
  2. Нас было 12 мобильных разработчиков, один разработчик занимался изучением фреймворка и системы CI.
  3. Около ~ 5–10% ложных негативов.

Остальные фреймворки, такие как Robotium и Calabash, больше не находятся в активной разработке.

Основное сходство между этими фреймворками заключается в том, что они представляют собой фреймворки для тестирования черного ящика.

Тестирование черного ящика

Что такое тестирование черного ящика? Это метод тестирования материала извне, не зная, что происходит внутри.
В мобильных устройствах E2E-фреймворки черного ящика по существу проходят по иерархии представлений, ищут элемент (если он не найден, засыпает, продолжает цикл таким образом до определенного времени ожидания), затем взаимодействует с этим представлением. Те же принципы применяются в веб-черном ящике E2E.

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

Тестирование черного ящика + React Native

E2E становится еще более нестабильным при использовании в приложениях, поддерживающих реакцию…

Рендеринг

В нативных приложениях есть только один поток, отвечающий за рендеринг пользовательского интерфейса (основной поток).
С React Native это немного сложнее, уникальная архитектура React Native усложняет систему, его рендеринг пользовательского интерфейса начинается с согласователя, который вычисляет, какие части пользовательского интерфейса были изменены. Это делается в потоке JavaScript, который затем передается через асинхронный мост и транслируется в собственные инструкции для основного потока для визуализации реального макета.
Благодаря этому механизму асинхронного рендеринга он использует, теперь есть два потока, управляющие рендерингом, поэтому у фреймворков тестирования черного ящика есть еще большие проблемы с управлением приложениями React Native.

Загрузка и разбор пакета

Когда приложение React Native запускается, оно загружает пакет либо с локального сервера упаковщика, либо из актива на устройстве, в любом случае это асинхронный процесс, который занимает неопределенное время. Фреймворк для тестирования черного ящика также должен будет бездействовать во время этого процесса, но как долго? Нет настоящего ответа.

Черный ящик был тупиком, нужен был другой подход ...

Детокс

Серый ящик, а не черный ящик

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

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

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

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

Использует EarlGrey и Espresso

Ведущие родные драйверы для серого ящика разработаны Google - EarlGrey для iOS и Espresso для Android. Эти фреймворки могут синхронизироваться с приложением, следя за тем, чтобы взаимодействовать с приложением только тогда, когда оно простаивает.

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

Вместо того, чтобы повторять действие / ожидание в пользовательском интерфейсе, они будут запрашивать внутренние ресурсы каждые несколько миллисекунд или прослушивать обратные вызовы от них, говорящие о том, что они теперь переключились в режим ожидания. Тест не будет продолжен до тех пор, пока все они не вернут «Да», и только тогда, когда приложение неактивно, оно будет взаимодействовать с пользовательским интерфейсом.

Не полагается на WebDriver

Detox не полагается на WebDriver, поскольку это не Интернет. Detox взаимодействует со своим собственным драйвером (который расширяет EarlGrey и Espresso) с помощью механизма отражения на основе JSON, что позволяет общей реализации JavaScript вызывать собственные методы непосредственно на устройстве.

Простой API

  1. Транспортир похож на API, написанный на JavaScript.
  2. Минимальный шаблон и очень небольшой процесс настройки.
  3. Кроссплатформенность. Тестовый код не знает, на какой платформе он тестирует, и может использоваться совместно с другими платформами.
  4. Синхронизировано: нет необходимости вручную синхронизировать тест с приложением, Detox изначально синхронизирован, он будет выполнять свои команды только тогда, когда приложение находится в режиме ожидания, больше не спит!
  5. Возможность отладки: использование собственных конструкций, таких как modern async-await, вместо помещения всего в очередь обещаний означает, что точки останова будут работать должным образом.

Поддержка React Native

Detox создан с нуля для нативных мобильных устройств и имеет глубокую первоклассную поддержку приложений React Native.

Мы обнаружили, что React Native в значительной степени переопределяет iOS и Android, поэтому, помимо базовой поддержки синхронизации EarlGrey и Espresso для нативных приложений, нам также пришлось создать специальные механизмы синхронизации для React Native.

Оценка ожиданий от устройства

Традиционно тестовые среды оценивают ожидания в тестовом сценарии, запущенном на компьютере. Detox изначально оценивает ожидания непосредственно в тестируемом приложении, запущенном на симуляторе. Это позволяет выполнять операции, которые раньше были невозможны из-за различий в объеме или производительности.

Как работает Детокс

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

  1. Test Runner: выполнение действия или ожидания (ожидание обещания)
  2. Тестер: ожидание сериализуется во вложенный вызов JSON
  3. Сервер: ретрансляция сообщения
  4. Испытуемый: Призыв ЭрлГрея через отражение метода
  5. Вызов будет выполняться только тогда, когда приложение простаивает
  6. Тестируемый: результат вызова отправляется обратно через веб-сокет
  7. Тестировщик: разрешить / отклонить обещание ожидания

Для получения более подробной информации о том, как работает Детокс, посетите документацию.

Автоматизация пользовательского интерфейса с помощью Detox

Вернемся к нашей пирамиде тестирования.

Итак, теперь у нас есть стабильная среда для сквозного тестирования. Но он все еще может быть нестабильным из-за проблем с сетью и сервером.

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

Реагировать-родной-переупаковщик

React-native-repackager - это насмешливый механизм для нашего реактивного JS-кода. По сути, он расширяет возможности упаковщика переопределять связанные файлы с любым другим файлом, по сути создавая простой способ имитации среды в react-native.

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

React-native-repackager также превращает Detox в среду автоматизации пользовательского интерфейса. Пирамида вся зеленая, никаких отговорок :) можно начинать тестирование!

Детокс в действии

Удивительно то, что серый ящик не только стабильнее черного ящика, но и намного быстрее. Больше не нужно спать или ждать Пока код не выполнит миллисекунду, когда приложение перейдет в режим ожидания. поэтому он примерно в 5–10 раз быстрее, чем решения типа «черный ящик».
Фактически, он настолько быстр, что запускает полный пакет проектов детоксикации (79 тестов) за 4 минуты.

  • Это собственные тесты E2E Detox, которые, конечно же, написаны с помощью Detox.
  • Симулятор, запускающий приложение, находится справа
  • Слева находится консоль, на которой выполняются наши тесты.
  • Мы используем Mocha в качестве тестовой программы, но вы можете использовать все, что захотите, люди уже успешно установили Detox с Jest.
  • Каждая строка, которую вы видите в консоли, представляет собой новый изолированный тестовый сценарий, поэтому он перезапускает все с самого начала и может быть сегментирован в будущем.
  • Как видите, это довольно быстро

Кросс-платформенный, правда? Где Андроид?

Многие спрашивают о поддержке Detox для Android. Это функция, которую с нетерпением ждут и в Wix.
Теперь открытый исходный код - прекрасная вещь, он может формировать сотрудничество, которое может вывести проекты на новый уровень.
Несколько месяцев назад с нами связался Симон Рац из KPN (крупная телекоммуникационная компания в Нидерландах) и предложил помощь с Detox для Android. С тех пор он практически стал членом команды Detox, внедряя ключевые функции в нашу предстоящую поддержку Android.

Посмотрим, как это выглядит

Это тот же набор тестов, который мы использовали для тестирования нашей реализации iOS. Его практически не трогали, так мы могли гарантировать, что наш API действительно кроссплатформенный. Detox для Android почти готов, на самом деле, очень немногих вещей не хватает, чтобы узнать больше о нашем выпуске Android, следите за нашей страницей релизов на github.

Детокс - это проект TDD

  1. Он имеет 100% покрытие кода и настроен на сбой сборки, если он становится ниже этого.
  2. E2E API Detox протестирован с помощью Detox. Мы запускаем весь API Detox в специальном тестовом приложении при каждой сборке.
  3. Он предназначен для приема взносов: сборки запускаются на TravisCI, и принимаются только те материалы, которые соответствуют стандарту, мы стараемся оставаться открытыми и взаимодействовать с сообществом и очень рады получать любые виды помощь.


Я хотел бы поблагодарить членов команды Detox: Лео Натана, Тала Кола, Сергея Ильевского, Симона Раца. , Элад Богомольный, Даниэль Шмидт и всем остальным нашим внутренним и внешним участникам, спасибо, ребята, вы молодцы!

Резюме

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