Тестирование страниц входа и согласия может быть довольно сложным: та же самая двухфакторная аутентификация (2FA), которая обеспечивает безопасность ваших клиентов, также затрудняет написание автоматизированных тестов. В этой статье я расскажу, как написал Python-тесты, которые обходят 2FA и при этом не покушаются на безопасность клиентов. Для этого я использовал Selenium и разработал Slackbot.
Будучи QA-инженером в компании NMBRS, которая поставляет программное обеспечение для управления персоналом и расчета заработной платы, я должен был разработать автоматизированные тесты наших страниц входа и согласия, чтобы выяснить, где были проблемы в службе идентификации. Службу идентификации используют наши клиенты для входа в систему.
Поскольку мы работаем с конфиденциальной информацией, процесс входа требует службы аутентификации. Мы используем OAuth2.0, стандартный протокол авторизации, который также используется Facebook, Instagram и Whatsapp.
Было важно убедиться в хорошем тестовом покрытии, потому что в то время в моем отделе не было реализовано ни одного теста. Однако при разработке теста мы столкнулись с двумя серьезными проблемами:
-
OAuth2.0 управляет двухфакторной аутентификацией (2FA) и отправляет код аутентификации на электронный ящик или мобильный телефон. Поэтому автоматизация этого процесса стала трудной задачей, так как мы не могли связать его с электронным ящиком или мобильным телефоном. Автоматизированные тесты должны выполняться без каких-либо ручных действий, поэтому мы не могли связать их с учетной записью электронной почты или мобильным телефоном.
-
NMBRS использует shadow-rooted Selenium для автоматизации тестов, что обычно хорошо подходит, поскольку скрывает веб-разделы. В данном конкретном случае shadow-rooted веб-компоненты усложнили разработку тестов, поскольку тест должен найти эти shadow-rooted элементы и указать селениуму, как вводить текстовые элементы.
Чтобы решить проблему 2FA, я создал Slackbot, который бы подходил для Selenium тестов. Затем я развернул бота на локальном сервере NGROK, который позволил Selenium тестам получить доступ к нему через эндпоинт. Это позволило мне протестировать систему локально, что было необходимо для того, чтобы перед развертыванием в Azure DevOps убедиться, что все идет так, как ожидалось. Чтобы решить проблему с Selenium, я написал команду, которую найдете дальше в статье.
Вот проблемы, с которыми мы столкнулись во втором релизе, и то, как мы их решили:
В первом релизе продукт тестировался в целом с помощью агрегированного тестирования, которое запускает все в одном потоке, поэтому мы не могли найти точное место, где продукт дает сбой. Например, если служба идентификации ломается, клиент не может войти в систему.
Во втором релизе весь тест был разделен на юнит-тесты. Используя pytest, библиотеку Python, мы разработали юнит-тесты, чтобы выяснить, где именно ломается служба идентификации. Тесты должны были:
-
Определить, работает ли Slackbot, который помог нам обойти 2FA.
-
Проверить, доступен ли сервер веб-приложения. Это необходимо, потому что если сервер веб-приложения выйдет из строя, вся система будет скомпрометирована, включая тесты.
-
Проверить, правильно ли заполнена страница входа в систему, поскольку иногда команда UI/UX изменяет веб-компоненты, чтобы улучшить дизайн приложения или исправить ошибку, которая может нарушать работу службы идентификации. Например, если текстовое поле неправильно связано с именем пользователя или паролем, пользователь не сможет войти в систему.
-
Проверить, что Slackbot получает уведомление о необходимости кода аутентификации 2FA и извлекает код после получения уведомления.
-
Проверить, действителен ли код 2FA, полученный Slackbot.
-
Проверить, все ли профили на странице согласия разрешены.
-
Проверить, что после нажатия кнопки «разрешить» из url извлекается код, и подтвердить, что этот код был извлечен.
-
Получить токен доступа (access token) и рефреш токен (refresh token) через OAuth 2.0.
-
Сгенерировать новый токен доступа, который должен отличаться от предыдущих.
Шаги с 4 по 6 были самой трудной частью разработки тестов, их я рассмотрю более подробно ниже.
Подход к тестированию: Gherkin Reference
Одним из ограничений, которые я имел при создании этих тестов, было то, что они должны были следовать структуре тестов Gherkin Reference, которую использует NMBRS.
Gherkin — это строчно-ориентированный язык. Каждая строка начинается с ключевого слова и называется шагом. Основная цель строчно-ориентированного языка — помочь разработчику или QA-инженеру проследить, как тест выполняется на каждом этапе. В Gherkin сценарий состоит из одного или нескольких шагов и обычно имеет следующую структуру:
-
Given: шаг, на котором определяется предварительное условие теста.
-
When: шаг, на котором определяется действие, которое мы хотим протестировать.
-
Then: шаг, когда ожидаемый результат успешен.
-
And: дополнительные шаги, добавляемые к Given/When/Then, которые используются вместо повторения этих слов.
Ключевое слово «Scenario» является уникальным, и вы просто запускаете его один раз, в то время как «Scenario Outline» может иметь несколько примеров. Говоря более технически, он может работать как шаблон.
Например:
Scenario Outline: Check Login Given I access environment '<Environment>' on country '<Country>' When On login page, I click on Sign-In Button And On sign-in page, I fill in user '<User>' and password '<Password>' Then Check if the user is in start page '/start.aspx'
Таблица, использующая эти переменные, будет выглядеть следующим образом:
Examples: | Environment | Country | User | Password | | www.testenv.com | PT | gui | 1234 | | www.testenv.com | NL | thais | 123 |
Теперь самый главный вопрос: как мне удалось решить две основные проблемы, с которыми я столкнулся во время разработки?
Shadow Root (теневой корень) на веб-элементах
Распространенная проблема страниц входа в систему, с которой сталкиваются разработчики UI/UX, — это инкапсуляция. Большинство компаний используют мощную технику, Shadow DOM, чтобы скрыть детали реализации. Чтобы защитить продукт NMBRS, наша команда DevOps скрывает конфигурацию веб-компонента (например, CSS или JS) определенного элемента или даже раздела HTML. NMBRS использует Shadow DOM, чтобы скрыть детали реализации и связать множество shadow hosts (теневых хостов) с другими shadow roots (теневыми корнями). Это позволяет нам маскировать некоторые веб-компоненты в объектной модели документа (DOM).
Практическими словами, Shadow Root — это способ скрыть и, следовательно, защитить служебную информацию.
В этой части возникла первая проблема. Поскольку элементы были с теневым корнем, мне было трудно указать Selenium-автоматике найти эти элементы. Это было сложно, поскольку теневой корень блокирует все классы и идентификаторы от определенного элемента, что не позволяет найти его, как, например, обычную кнопку.
После некоторых исследований и помощи других тестировщиков я использовал приведенную ниже команду для поиска различных компонентов. Нужно было только изменить класс или id компонентов. Например, вместо ‘nmbrs-form’ можно было использовать ‘nmbrs-button’.
return document.querySelector(’nmbrs-form’).shadowRoot.querySelector(’div div.btn-container nmbrs-button’).shadowRoot.querySelector(’button#button’)
Как видите, есть два элемента Shadow Root. Это команда запроса, где querySelector() захватывает родительский компонент дочернего shadowRoot или конечного элемента. По сути, чтобы получить информацию внутри теневого хоста, в данном случае ‘nmbrs-form’, достаточно написать ‘.ShadowRoot’. Это позволило мне указать Selenium, какие компоненты нужно найти, несмотря на Shadow Root.
После настройки Selenium-автоматизации мне нужно было создать Slackbot для получения кода аутентификации 2FA. Как в реальной, так и в тестовой среде этот код обычно отправляется на электронную почту пользователя. Однако для автоматизации этого процесса в тестовой среде этот код отправляется в закрытый канал Slack. Этот канал принимает только сигналы, и никто, кроме инженеров отдела контроля качества, не имеет к нему доступа. Мы использовали Slack, потому что он является неотъемлемой частью нашего общения и рабочего процесса в NMBRS.
Обход 2FA с помощью Slackbot
Каждый сигнал, генерируемый в тестовой среде, поступает непосредственно в частный канал Slack. Из-за опасений по поводу безопасности пользовательских данных и политики NMBRS я создал Slackbot, чтобы получить код 2FA. Slackbot смог обеспечить безопасность, выполняя те же действия, что и обычный пользователь, и тестовую скорость, одновременно получая код.
Интеграция со Slack
Чтобы запустить Slackbot в Slack, мне нужно было интегрировать его с платформой. Я создал QA AUTHENTICATION — API для чтения писем с кодом 2FA на частном канале. Эта интеграция была основана на подписках на события: всякий раз, когда мы получали новое письмо от OAuth2.0, канал Slack уведомлял Slackbot.
#EVENT SUBSCRIPTION TO KNOW WHEN A NEW FILE IS SHARED @slack_event_adapter.on('file_shared') def data_handler(payload): if automated_test: event = payload.get('event', {}) file_id = event.get('file_id') SlackR = client.files_info(file=file_id) SlackMessage = SlackR.data.get("file").get('plain_text') if SlackMessage.find(login_email)!=-1: code = SlackMessage.split(" ") global auth_code auth_code = int(code[4])
Одним из недостатков Slackbot является то, что его нельзя запустить на Azure Pipelines. На наших виртуальных машинах (ВМ) не установлена платформа Slack. В приложении Slack использовался NGROK, поскольку тесты проводились локально на моем компьютере.
NGROK — это фреймворк локального сервера, который позволяет вывести веб-сервер, работающий на вашей локальной машине, в интернет. Кроме того, он предоставляет веб-интерфейс в реальном времени, с помощью которого можно исследовать весь HTTP-трафик.

Slackbot также функционирует как Flask REST API, с которым автоматизированный Selenium-тест и приложение slack взаимодействуют через эндпоинты.
Важно убедиться, что Slackbot получает уведомление об отправке кода аутентификации 2FA и что Slackbot получает код после его отправки. Это доказывает, что код 2FA у нас самый новый и что он действителен.
Переходим к самому интересному. Я хочу поделиться с вами правильным движением между автоматизированным тестом (Selenium), Slackbot и приложением Slack.
Как взаимодействуют Slackbot, приложение Slack и Selenium-тесты

-
Когда Selenium-тест начинает выполняться, он отправляет HTTP-запрос в приложение Slack, чтобы сообщить Slackbot о начале прослушивания канала.
-
Когда тест достигает страницы 2FA, Slackbot запрашивает код 2FA.
-
Бот прослушивает все недавно пришедшие сообщения с условием, что в сигнале должно быть письмо с логином Selenium-теста.
-
После того как Slackbot распознает письмо, он запрашивает тело сообщения.
-
Приложение Slack извлекает основное сообщение, а Slackbot помещает его в строку.
-
Используя библиотеку Python, бот подхватывает код 2FA.
-
Slackbot отправляет код обратно в Selenium-тест.
После завершения 2FA тест переходит на страницу согласия, где он видит различные профили, связанные с разными бухгалтерами. Поэтому, повторюсь, очень важно убедиться, что всем профилям, которые появляются на странице согласия, разрешено там появляться. Мы не должны видеть чужие профили в целях безопасности. Если мы видим чужой профиль, это означает, что мы можем получить доступ к информации других людей, а это противоречит политике аутентификации и хранения данных.
После этого автоматический тест должен нажать на кнопку «разрешить». Код разрешения авторизации (authorisation grant code) будет получен в URL через определенный эндпоинт и отправлен в приложение Flask. Затем юнит-тест захватывает код, чтобы определить, действителен он или нет.
Код разрешения авторизации важен, поскольку это единственный способ получить токен нового доступа и рефреш токен. Если у вас их нет, вы не сможете получить доступ к какой-либо информации в приложении NMBRS.
Наконец, с этим кодом предоставления полномочий последним шагом будет обращение к конечной точке ‘/connect/token’ для получения нового ‘access_token’ и ‘refresh_token’ с последним ‘refresh_token’.
И последнее, но не менее важное: после генерации нового токена доступа мы хотим проверить, отличаются ли старый и новый токены. А они должны! Эта последняя часть проверяется путем совершения POST-запроса от сервиса идентификации. В заголовке мы добавляем тип токена доступа (в данном случае ‘Bearer’) и рефреш токен. После выполнения запроса сервер получит ответ с новым токена доступа в теле сообщения. На этом процесс тестирования завершается!
# GET ACCESS TOKEN VIA REFRESH TOKEN def get_access_token(): header = {'Content-Type': 'application/x-www-form-urlencoded', 'Authorization':basicAuthorization_encoded} payload = {'refresh_token':refresh_token} response = requests.post(baseIdentityURL + + '/connect/token', data=payload, headers=header) if response.status_code==200: responseJSON = response.json() new_access_token = responseJSON['access_token'] if new_access_token!=access_token: tests["test_message"] = 'Access Tokens are different.' return tests["test_message"] = 'Access Tokens Not Received via refresh token.' return
Плюсы и минусы моего подхода
Как и любой другой подход, этот подход имеет свои плюсы и минусы.
Давайте начнем с плюсов:
-
Slackbot может протестировать каждую NMBRS среду.
-
Автоматизированное тестирование быстрее, чем выполнение теста вручную: в среднем на получение письма и ввод кода человек тратит 2-3 минуты; моему боту требуется всего 10 секунд.
-
Кроме того, тест может работать вечно, а его зависимости требуют меньше поддержки.
Минусы:
-
Для полноценного запуска автоматизированного теста необходимо, чтобы одновременно было открыто несколько инструментов, и он зависит от нескольких платформ. Если одна из них выйдет из строя, бот тоже откажет.
-
Наличие нескольких зависимостей снижает производительность теста и увеличивает время, необходимое для его выполнения. Однако это все равно быстрее, чем ручное тестирование.
Учитывая эти плюсы и минусы, как мы можем улучшить тесты? Чтобы тесты было проще обслуживать и легче выполнять, важно перейти от тестов, созданных локально на компьютере, к Azure DevOps Pipelines. Следующий релиз мы сделаем на Azure DevOps. Миграция позволит устранить зависимости от Slackbot и расширить эти тесты для живых сред. На наших виртуальных машинах не установлен Slack. По этой причине игнорирование интеграции Slack путем обхода 2FA с помощью конкретной электронной почты будет отличным решением, которое будет работать как в живых, так и в тестовых средах.
Мы внедрили автоматизированное тестирование в NMBRS впервые, и оно оказало огромное влияние:
-
Текущий выпуск автоматизированных тестов позволил команде QA сэкономить время на тестировании.
-
Это позволило нам тестировать каждый день, чего мы не могли делать раньше при ручном тестировании.
-
Благодаря этому внедрению DevOps может быть лучше информирован о происходящем и действовать до того, как произойдет сбой продукта.
Мигрировав на Azure Pipelines и устранив зависимости, мы еще больше оптимизируем этот процесс.
Мы прошли от точки незнания того, как создавать автоматизированные тесты, до создания тестов с таким большим эффектом — это был продуктивный путь обучения, и я с нетерпением жду третьего релиза. Если вы хотите узнать больше о моей разработке тестов, предлагаю ознакомиться с некоторыми ключевыми ресурсами, которые я использовал.
Через пару дней состоится открытый урок, посвященный автоматизации тестирования на Python: поговорим о профессии и ее перспективах. Обсудим, какие навыки необходимы для работы и какие требования предъявляют к кандидатам на собеседованиях. Также разберем современные технологии автоматизации тестирования и преимущества использования автотестов.
ссылка на оригинал статьи https://habr.com/ru/companies/otus/articles/738280/
Добавить комментарий