Подготовка сцены

Мы все это видели: чем больше становится организация, тем сложнее становится наладить значимое и эффективное общение между командами. Это особенно очевидно, когда стимулы не совпадают. Часто команды разработчиков заинтересованы в том, чтобы построить как можно больше в кратчайшие сроки. С другой стороны, команды QA заинтересованы в снижении риска, присущего кодовой базе / приложению, до приемлемой степени. Проблема очевидна: в то время как группы разработчиков оптимизируются для скорости, команды QA оптимизируются для обеспечения корректности. Это несоответствие стимулов приводит к разочарованию и эмоциональному выгоранию между этими командами и внутри них.

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

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

Состояние дел

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

  1. QA связывается с разработчиком или командой разработчиков, предположительно ответственными за исправление. Они делают это с помощью инструмента связи, такого как Slack, или путем создания проблемы в трекере, таком как Jira.

2. Затем специалист по контролю качества переходит к разговору с «командой разработчиков Checkout».

3. QA остается в замешательстве и не знает, что делать дальше.

За этим последует обмен мнениями между командами QA и разработчиков, которые пытаются воспроизвести проблему в разных средах разработки, при этом делятся снимками экрана и записями и пытаются отыскать соответствующие журналы очевидной проблемы. И все это, когда они бьются головой об стену, потому что проблемы возникают только при кажущихся случайными обстоятельствах, которые невозможно определить. Вдобавок ко всему, вполне вероятно, что после нескольких дней, когда эта проблема сохранялась и вертелась в JIRA, ни одна команда разработчиков уверенно не заявила, что владеет ошибкой, не говоря уже о том, чтобы работать над исправлением.

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

Можем ли мы сделать лучше?

Конечно можем! Но прежде чем я покажу вам, как это сделать, позвольте мне представиться: я Хуан, и я работаю инженером-программистом в Undefined Labs. Мы работаем над инструментами разработчика и считаем, что пришло время коренным образом изменить способ взаимодействия групп тестирования и разработки и значительно улучшить методы тестирования приложений в организациях. В этом посте я хотел бы показать вам возможности Scope для ручного веб-тестирования.

Чтобы лучше объяснить наш подход, давайте вернемся к нашему предыдущему сценарию, на этот раз с помощью Scope:

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

Представляем Scope for Chrome

Когда мы приступили к созданию Scope, мы в основном ставили перед собой задачу решить проблемы разработчиков. И хотя за исправление ошибки в конечном итоге несут ответственность разработчики, мы увидели в Scope возможность навести мост между QA и командами разработчиков. Scope for Chrome - наш первый шаг к построению этого моста.

Несмотря на то, что многие фреймворки, SDK и агенты для тестирования, которые мы создали на сегодняшний день, предназначены для разработчиков, с самого начала было ясно, что потребности и инструменты QA совершенно разные. Создавая Scope for Chrome, мы хотели создать самый простой способ для всех создавать содержательные ручные тесты браузера. Таким образом, единственное требование для использования Scope for Chrome - это (1) установить наше расширение для браузера и (2) знать, как использовать веб-браузер.

Это действительно так просто:

После того, как кто-либо запишет ручной тест с помощью Scope for Chrome, отчет будет создан автоматически. Этот отчет об испытаниях включает:

  • Действия пользователя, такие как щелчки или нажатия клавиш.
  • HTTP-запросы с их заголовками и полезными данными.
  • Ответы серверной части и даже запросы к базе данных, запускаемые в результате запроса.
  • Журналы консоли.
  • Исключения.

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

Как это работает

Проще говоря: когда пользователь нажимает кнопку Начать запись, Scope For Chrome начинает прослушивать и записывать все, что происходит на вашей текущей вкладке.

Более подробно, чтобы добиться этого, наши усилия состоят из трех частей:

  • Прослушивайте и записывайте пользовательские события, такие как щелчки мыши, нажатия клавиш на клавиатуре и исключения, происходящие на вкладке.
  • Обезьяна заполнила XHR и fetch, введя код в тестируемую вкладку. Каждый запрос создает новый диапазон (отдельная единица работы согласно терминологии OpenTracing), который затем распространяется на серверную часть.
  • Слушайте запросы main_frame (документ, который загружается для фрейма верхнего уровня). Это первый запрос, который ваш браузер выполняет при переходе на новую страницу. Для этого мы используем API расширения webRequest.

Конечно, это всего лишь беглый взгляд на то, что делает Scope for Chrome. Ничего из этого не было бы возможно без работы нашего агента javascript, других наших агентов (Python, iOS, .NET, Java, Golang), нашего бэкенда, способного принимать и обрабатывать тестовые данные и распределенные трассировки, а также наш специализированный веб-интерфейс для отображения тестов в интерактивном и структурированном виде.

P.S. Дополнительную информацию см. В Техническом дополнении ниже.

Что дальше?

С постоянно растущей сложностью современного программного обеспечения появляются более сложные команды разработчиков программного обеспечения. Точно так же, как команды работают над улучшением интерфейсов между распределенными сервисами, мы должны улучшить нашу совместную работу и взаимодействие между командами. Мы считаем, что Scope for Chrome может помочь решить самые неприятные проблемы, связанные с отсутствием прозрачности при ручном тестировании, и поможет преодолеть разрыв между QA и Dev.

Вы можете узнать больше о Scope for Chrome здесь.

Техническое приложение: технические проблемы, возникшие при создании Scope for Chrome.

1. Патчить обезьяну сложно

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

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

Это может быть расширено для других целей. Например, в веб-приложении вы можете заменить console.log функцией, которая не только регистрирует сообщение, но и добавляет дату, когда функция была вызвана.

Вот пример:

const log = console.log
console.log = function() {
  log.apply(console, [new Date().toISOString(), ...arguments])
}

Базовое исправление обезьяны для window.fetch прост (обратите внимание, что это всего лишь пример и не готов к использованию в качестве производственного кода):

const oldFetch = window.fetch
window.fetch = (...args) => {
   // do something here
   return oldFetch(...args)
}

Все становится еще интереснее, когда вы хотите делать там асинхронные вещи, например, общаться с помощью фонового скрипта:

const oldFetch = window.fetch
 window.fetch = (...args) =>
  new Promise(resolve => {
   asyncCommWithBackground().then(newRequestInfo => {
    const newFetchArgs = [...args, ...newRequestInfo]
    resolve(oldFetch(...newFetchArgs))
   })
  })

Этот паттерн довольно мощный. Но с большой силой приходит большая ответственность. За счет исправления обезьяны мы замедляем каждый запрос на активной вкладке на время, необходимое для выполнения asyncCommunicationWithBackground.

А вот пример выполнения чего-то с результатом выборки:

window.fetch = (...args) =>
 new Promise(resolve => {
  asyncCommWithBackground().then(newRequestInfo => {
   const newFetchArgs = [...args, ...newRequestInfo]
   resolve(oldFetch(...newFetchArgs)).then(fetchResult => {
    // do something with fetchResult
    return fetchResult 
   })
  })
 })
}

Вы можете немного упростить код с помощью async / await, но будьте осторожны. Вы, вероятно, захотите узнать, не удалась ли ваша выборка, для чего вы бы использовали try / catch. Но если вы сделаете это, вы не сможете исключить распространение на потребителя, а этого сценария лучше избегать. Здесь самое главное помнить: исправление обезьяны, сделанное правильно, должно быть прозрачным.

Чтобы что-то сделать с данными ответа, например добавить его в диапазон в качестве тега или метаданных, вам нужно быть осторожным с клонированием вашего ответа перед этим, поскольку это поток, и его можно использовать только один раз.

Если вы хотите углубиться в этот шаблон, мы создали репозиторий с небольшим проектом функционирующего расширения Chrome, который задерживает все ваши запросы fetch. Узор выделен здесь.

Альтернативой этому решению является использование API webRequest с такими хуками, как onBeforeSendHeaders, но на данный момент этот API не позволяет захватывать полезные данные ответа, что было требованием для Scope.

2. Установить патч Monkey в браузере еще сложнее.

Как оказалось, если вы хотите повлиять на переменную window вкладки, которая нам нужна для исправления обезьяны, скрипта содержимого недостаточно. Вам нужно выполнить код, подобный показанному здесь. Это означает обработку вашего кода как строки. Есть некоторые альтернативы, такие как использование function.toString () и макросы babel для оценки переменных во время сборки, но дополнительная сложность сводит на нет цель, поскольку ваши исправленные функции обезьяны в любом случае не должны быть большими.

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

3. Асинхронная отправка ответов.

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

4. Объединение расширения

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

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





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

5. Совместимость с браузером.

Проблема с совместимостью браузеров не решается с помощью расширений. Хотя мы еще не углубились в это, похоже, что у web-ext большой потенциал.

6. Команды хоста

Наш агент javascript получает некоторые из своих метаданных с помощью команд host. Но вы используете расширение браузера, так что это не вариант.

Тогда возникают некоторые вопросы:

  1. Откуда получить учетные данные? Для трассировки, отправляемой на бэкэнд, требуется конечная точка API и ключ API.
  2. Как мне рассчитать смещение NTP на моем компьютере, необходимое для точных измерений отметки времени в представлении трассировки? Когда говорят о распределенных трассах, важно разрешение и точность порядка микросекунд и даже наносекунд, поскольку трассы часто создаются на разных машинах. Любое небольшое смещение может испортить ваши данные.
  3. В будущем: как мне получить код этого конкретного файла и номер строки, вызвавшей исключение?

Есть разные способы ответить на эти вопросы. Например, мы можем решить номер 1, зарегистрировав наше расширение с помощью файлов cookie браузера. Это позволит расширению отправлять аутентифицированные запросы на наш сервер. Однако это рискованно, так как для этого требуется SameSite = None cookie. Номер 2 сложен, поскольку нет решений внешнего мира - нам нужны права хоста. Номер 3 можно решить так же, как и номер 1, но, опять же, это рискованно.

Вариант, который отвечает на все 3 вопроса, - это использование нашего приложения Scope Native через собственный API обмена сообщениями. В собственном приложении уже настроена конечная точка API по вашему выбору, и у него есть доступ к ключу API, который решает вопрос номер 1. Оно также может запускать команды хоста, так что решает номер 2 и номер 3. Недостаток в том, что мы соединяем наше расширение с другим продуктом, но с учетом наших текущих и будущих требований, это кажется наилучшей возможной альтернативой.

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

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

Ваш путь к лучшему проектированию за счет лучшего тестирования начинается с Scope.