Как докеризовать свои сквозные приемные тесты

1656597985 kak dokerizovat svoi skvoznye priemnye testy
VKuRIyPcfnVrGvjRB3oe6NrQ026qn9DzmXru
Источник

Эта статья служит руководством с использованием изображений Selenium Docker вместе с CodeceptJS и Express-сервером.

В нем мы рассмотрим:

  • Что такое приемное тестирование E2E?
  • Зачем использовать Docker?
  • Слабо связанные инструменты тестирования
  • Слои инструментов тестирования
  • Создание тестового проекта

Тестирование приема E2E

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

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

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

Почему Docker?

Создание и исполнение тестов E2E часто считается нестабильным и сложным процессом. Он требует много настроек, которые все равно могут легко выйти из строя при запуске на разных машинах или в среде CI (непрерывная интеграция). Установка и поддержка различных браузеров и веб-драйверов как для локальных, так и для тестов CI требует времени. И даже после завершения он все равно может выйти из строя из-за простых проблем, например, если разрешение экрана на локальных машинах разработчика или в CI отличается.

Также применяются стандартные преимущества Docker: отсутствие необходимости сталкиваться с совместимостью ОС или установление зависимостей. Чтобы запустить сервер Selenium, необходимо установить Java (или по крайней мере запустить/остановить его явно). Для запуска Express вам понадобится Node.js, а для Chrome вам понадобится сам Chrome и ChromeDriver.

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

Слабо связанные инструменты тестирования

При написании тестов E2E доступно несколько фреймворков, и новичку может трудно понять, что выбрать и вложить время. Если вы выберете неправильно, вы потеряете много времени.

Вот здесь и появляется CodeceptJS. CodeceptJS — это платформа для тестирования, которая использует подход к разработке, ориентированной на поведение (BDD), с языком API, который легко понять и использовать неинженерам. Однако, возможно, даже важнее, что он не зависит от сервера. Он написан поверх нескольких популярных библиотек тестирования (например, WebDriverIO или Puppeteer), а его единственный высокоуровневый API связывается с любой, которую вы выберете. В это верят творцы

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

Слои инструментов тестирования

CseVMJoB7kKBDdz-oWzad7JGicjB-7V80JBw
Некоторые из различных продуктов доступны на каждом уровне моделирования взаимодействия пользователя с обозревателем

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

Сначала следует упомянуть Selenium, долговременный проект с активно используемым набором инструментов, который сегодня состоит из Selenium WebDriver, Grid, Server и IDE. Создавая эти инструменты, они установили многие отраслевые стандарты, часто названные в честь продукта Selenium, из которого они вышли. Это можно увидеть в «Selenium WebDriver» и «Протоколе провода WebDriver», созданном при его разработке. Применяемые будут показаны более подробно ниже.

браузер

Любой веб-браузер: Chrome, Firefox, Internet Explorer, Safari, Opera и т.д. В документации его часто называют агентом пользователя.

Протокол W3C WebDriver

Протокол WebDriver – это нейтральный для платформы и языка способ взаимодействия с веб-браузерами. Он определяет общий веб-сервис RESTful, который использует JSON через HTTP в парах запрос/ответ. Он позволяет манипулировать элементами DOM из внешнего источника, а также навигацию к веб-страницам, ввод пользователя, выполнение JavaScript и т.д.

Первоначально написанный Selenium для Selenium WebDriver, теперь этот протокол достиг этапа редакции черновика, став официальным стандартом W3C.

Остальные протоколы выходят, но здесь не будут детально рассмотрены. Все пояснения будут предусматривать бэкенд, реализуемый ведущим протоколом WebDriver.

Еще одним известным протоколом является протокол Chrome DevTools, используемый Puppeteer. Puppeteer не использует Selenium Server и поставляется с последней версией Chromium, предназначенной для локального использования. Если вы хотите запустить Puppeteer в Docker, вы можете использовать образ CodeceptJS (который поставляется вместе с Puppeteer и Nightmare) или следуйте официальному руководству по созданию специального образа, который может его поддерживать.

Веб-драйверы браузера

Это специфические для браузера реализации протокола проводов WebDriver, например, ChromeDriver для Chrome или GeckoDriver для Firefox. Каждый из них действует как отдельный сервер для получения запросов от клиента, где используется API WebDriver (обычно там, где проводятся тесты). Для связи с назначенным браузером, правильная реализация WebDriver должны быть установлен.

Сервер Selenium

Если тесты выполняются на той же машине, на которой они определены, используемая реализация API WebDriver на стороне клиента (описанная ниже) может взаимодействовать непосредственно с браузером WebDriver, и сервер Selenium не нужен.

Однако если тесты должны выполняться на другой машине, то ли в CI, в настройке Selenium Grid на нескольких машинах или виртуальных машинах (VM), на удаленной платформе тестирования, такой как BrowserStack или SauceLabs, или в Docker, тогда Selenium используется сервер. Он действует как прокси-сервер для передачи запросов от клиентского API WebDriver к правильному браузеру WebDriver и передает ответ от браузера.

AC97-bPidMqMbZ51NLXSPf3gwjBgGxw5b4Oi
Как мы увидим позже, «машина» также может быть заменена на «контейнер»

Реализация WebDriver на стороне клиента

Различные инструменты реализуют ведущий протокол WebDriver на стороне клиента. Здесь протокол можно рассматривать как API для отправки запросов в браузер через описанные выше слои. Многие инструменты, использующие этот протокол, являются полноценными фреймворками, например WebDriverIO, включающими собственные тестовые программы.

Другие реализации включают: оригинальный Selenium WebDriver, Protractor, Appium и т.д.

Библиотеки каждой из них имеют целью достижение тех же результатов, но с несколько разными фокусами и реализацией API. Это может быть таким же основным, как транспортир browser.get(url) по сравнению с WebDriverIO browser.url(url).

Один API для управления всеми

Как описано в начале этой главы, здесь вступает в игру CodeceptJS. Он ссылается на другие реализации протокола WebDriver на стороне клиента (или другие) как «помощники» и позволяет указать помощник, который вы предпочитаете, используя один язык API. CodeceptJS не имеет значения, какой протокол используется выбранным помощником.

WebDriverIO, Puppeteer, Protractor, Nightmare и Appium – это все доступные ассистенты.

У CodeceptJS предыдущая команда была бы I.amOnPage(url) независимо от того, какой помощник был избран. Это значит, что если вы хотите переключить свой бэкенд на одного из других поддерживаемых помощников, ваши тесты не придется переписывать. По желанию можно перезаписать или добавить в стандартные методы API с помощью специальных классов.

Создание тестового проекта

С таким количеством слоев это кажется сложным, но между сценарием инициализации CodeceptJS и изображениями Docker мы можем быстро получить рабочий пример.

Что мы будем производить

mb81mFfkSipoaHtimDmOLqloRRpCOAlev4RS
Пока будут использоваться два контейнера, хотя это может быть продлено

Мы напишем простой тест CodeceptJS, указав серверный помощник WebDriverIO, который будет общаться с удаленным браузером в автономном контейнере Docker Firefox. Мы будем использовать программу Express «hello world», но ее можно заменить любой программой, которую вы хотите.

2kWArT3EpzQgqymSONorN81cpb3rcF7WPd2L
В скором времени для запуска программы Dockerized и всех тестовых наборов понадобятся всего две команды

После того как мы все настроим, мы сможем запустить только две команды для запуска тестов:

  • docker-compose up --build
  • docker exec -it app npm run test:e2e

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

Предпосылки

  • Docker для любой машины, на которой вы разрабатываете.
  • Вы также можете установить Node.js и npm для локальной разработки и отладки, но их можно полностью запустить в Docker.

Структура файла

Ниже мы создадим структуру файла. Вы можете увидеть рабочий пример Github.

|-- .gitignore 
|-- output/
|-- Dockerfile
|-- app.js
|-- docker-compose.yml
|-- package.json
|-- package-lock.json
|-- e2eTests/
    |-- common_test.js
    |-- docker.conf.js

Зависимости

Сначала мы создадим наш package.json с Express как зависимостью и CodeceptJS и WebDriverIO как зависимостью разработчика.

{
  "name": "example-standalone-firefox",
  "version": "1.0.0",
  "description": "Example of Dockerizing E2E testing",
  "scripts": {
    "start": "node app.js",
    "test:e2e": "codeceptjs run --steps --verbose --config=./e2eTests/docker.conf.js"
  },
  "dependencies": {
    "express": "^4.16.3"
  },
  "devDependencies": {
    "codeceptjs": "^1.2.0",
    "webdriverio": "^4.12.0"
  }
}

Мы также включили два сценария, один для запуска программы Express, который мы добавим (npm run start), и один для запуска нашего теста CodeceptJS (npm run test:e2e).

codeceptjs run --steps --verbose --config=./e2eTests/docker.conf.js

--steps отлично подходит для отображения результата в терминале во время выполнения тестов, while --verbose еще больше расширяет уровень детализации. --verbose вероятно, не требуется как стандарт, но хорошо, чтобы увидеть, как работает пример. --config показывает нам путь к файлу конфигурации бэкенда, в этом случае сохраняется в отдельном e2eTests каталог.

Наше приложение

Дальше нам понадобится приложение для тестирования. Для этого мы запустим приложение Express «hello world». app.js.

const express = require('express');

const app = express();

app.get('/', (req, res) => res.send('Hello World!'));

const server = app.listen(3000, () => {
    const port = server.address().port
    console.log(`Example app listening on port ${port}`)
 })

Вы можете просмотреть это с помощью npm run start а потом собирается localhost:3000 в вашем браузере.

Тестовая конфигурация

Для CodeceptJS требуется два файла, конфигурационный файл и тестовый файл. Тестовый файл очень прост: он проверяет, можно ли получить доступ к программе, сохраняет снимок экрана и проверяет, можно ли увидеть на странице текст «Привет».

Feature('Basic test');

Scenario('navigate to homepage', I => {
  I.amOnPage('
  I.saveScreenshot('frontpageScreenshot.png');
  I.see('Hello');
});

Первый признак того, что мы будем использовать несколько контейнеров Docker, показан здесь в использовании app:3000 а не localhost:3000. localhost можно понять только из одного контейнера. Если команда выполняется из другого контейнера (в данном случае Firefox в нашем втором контейнере Selenium), то она требует более четкой ссылки. Мы могли бы использовать IP-адрес первого контейнера напрямую, но использование имени контейнера гораздо легче читать.

В этом случае, app будет имя контейнера, в котором запускается приложение, поэтому мы можем использовать app:3000. Не волнуйтесь, если вы еще не придерживаетесь этого, видя, как наши docker-compose.yml структурированный поможет.

Нам также необходим основной конфигурационный файл. Это можно написать в JSON или JS, но здесь мы используем JS. Давайте посмотрим на это:

exports.config = {
  tests: './*_test.js',    // how to know which files are test files
  output: './output',      // where to save screenshots
  helpers: {
   WebDriverIO: {               // which backend helper to use
     url: '    // a base URL to start on
     host: 'firefox-container', // identifying where selenium runs
     browser: 'firefox',        // a series of config options
     smartWait: 5000,              
     waitForTimeout: 10000,
     desiredCapabilities: {        // for a demo app we do not want 
         acceptInsecureCerts: true,   to worry about SSL certs
     }
   },
  },
  name: 'codeceptjs-docker',
};

Настройка Docker

Возвращаясь к диаграмме выше в разделе «Что мы будем производить», мы видим, что мы будем использовать два контейнера Docker. Они должны знать друг друга и уметь общаться. Один из них будет содержать нашу программу и тесты, а другой – Selenium Server, GeckoDriver и Firefox, поэтому нам не нужен Firefox, установленный на нашей локальной машине.

Docker Compose — это инструмент для определения и запуска многоконтейнерных программ Docker. Он запускает контейнеры Docker с помощью команды docker-compose upи останавливает их с помощью docker-compose down. Если используется определенный пользователем Dockerfile, --build используется для его постройки или в первый раз docker-compose up запущен или если в файле Docker были внесены изменения. docker-compose.yml это файл, определяющий, что up команда подойдет.

Наш следующий шаг – создать это docker-compose.yml. Это сильно зависит от отступления.

version: "2"        // which version of compose syntax you are using
services:
  app:
    container_name: app  // explicit so we can use this for app:3000
    build: .             // a self defined Dockerfile, see below
    ports:               // exposes port 3000 (where express runs)
      - "3000:3000"         to other containers, and to our local       
    depends_on:             browser
      - firefox-container
    volumes:             // maps so changes to these can be seen
      - ./e2eTests:/e2eTests
      - ./package.json:/package.json
      - ./package-lock.json:/package-lock.json
      - ./.gitignore:/.gitignore
      - ./app.js:/app.js

  firefox-container:      // we'll look at this below
    container_name: firefox-container
    image: selenium/standalone-firefox:3.12.0-americium
    volumes:
      - /dev/shm:/dev/shm
    ports:
      - "4444:4444"

Для нашего сервера Selenium, драйверов и браузера мы используем предварительно определенное изображение, доступное в общедоступном Docker Hub, которое называется selenium/standalone-firefox. Мы указываем, какую версию мы хотим, 3.12.0-americium. Если бы мы не указали это, последнее изображение использовалось бы по умолчанию (что неплохо). Как рекомендуется, мы настраиваем его на общий доступ к памяти хоста, чтобы предотвратить сбой запуска браузера, и открываем порт 4444, порт Selenium по умолчанию. Мы также сопоставляем это с портом 4444 на нашей локальной машине, что позволяет нам посетить localhost:4444/wd/hub/static/resource/hub.html в нашем браузере.

Для наших app контейнера, мы не просто используем изображение, созданное кем-то другим, а пишем Dockerfile, чтобы определить, как строится наше приложение. Так же, как и selenium-firefox контейнера мы открываем порт, в этом случае 3000, поскольку именно там по умолчанию работает Express. Отражая это с помощью 3000:3000 мы можем посетить localhost:3000 пока приложение запускается в Docker, чтобы увидеть ее в нашем локальном браузере.

Наш Dockerfile использует public node:carbon image как основу, устанавливает рабочий каталог, копирует некоторые файлы из нашей локальной машины в контейнер, запускает npm install чтобы контейнер имел все необходимые зависимости, а затем запустил файл npm start команду, которую мы указали.

FROM node:carbon 
WORKDIR ./ 
COPY ./package.json ./package-lock.json ./app.js ./ 
RUN npm install 
CMD [ "npm", "start" ]

Это означает, что когда docker-compose up --build запущен, он будет выполнять эти шаги, в результате чего наша программа будет готова и работает на порту 3000.

Примечание: The --build флаг нужен только в первый раз docker-compose up запущен или если были внесены изменения в наш файл Docker или шаги, выполненные в нем. Например, если мы добавили другую зависимость в наш package.json тогда Docker не знал бы об этом, если бы мы не перестроили наш образ, как npm install выполняется в Dockerfile.

Запуск тестов

Теперь у нас есть простая программа, написанные для нее тесты и конфигурация Docker Compose, которая будет запускать и нашу программу, и сервер Selenium, и Firefox.

Мы можем начать использовать все это docker-compose up --build.

Для выполнения команд внутри запущенный контейнер Docker, docker exec можно использовать из другого окна терминала. Формат:

docker exex <flags> <container_name&gt; <команда>

Команда, которую мы будем использовать:

docker exec -it app npm run test:e2e

Теперь мы можем видеть, как выполняется наш тест и видеть каждый шаг, как он выполняется! Отсюда мы можем расширить то, что делает наш тест, добавить дополнительные тесты (заканчивая имена файлов на _test.js), и используйте те же две команды, чтобы запустить их. Большая настройка не требуется.

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

Заключительные слова

SeleniumHQ также создает изображения Docker для тестирования Chrome и изображения для использования Selenium Grid для одновременного запуска нескольких экземпляров Chrome и Firefox.

CodeceptJS также содержит инструкции по запуску CodeceptJS в Docker, поэтому его не нужно указывать как зависимость в вашем приложении.

Более техническое, но все же на начальном уровне описание того, как работает Docker, можно увидеть в первой главе публикации, которую я написал под названием Руководство для начинающих по службе Elastic Container Service от Amazon.

Спасибо, что прочли?

Обновление:
Недавно я написал настройки тестов CodeceptJS e2e для тех, кто ищет следующие шаги в тестировании сложных программ.

Ресурсы

Добавить комментарий

Ваш адрес email не будет опубликован.