Немного про Selenoid
Если вы читаете эту статью, то наверняка слышали о Selenoid. Это мощное решение написанное на Go от компании aerokube для управления Docker-контейнерами, в которых «завёрнуты» все необходимые программы и драйверы для тестирования в браузерах или на Android-эмуляторах. Как утверждают производители Selenoid, их решение потребляет намного меньше ресурсов, чем, например тот же Selenium. В то время, как первый имеет удобный веб интерфейс (в документации к Selenium нет никаких упоминаний про UI) и также возможность параллельного запуска тестов. У Selenoid также есть отличная поддержка, большое коммьюнити и достаточно хорошая документация .
Отмечу, что Selenoid работает только на Linux. За исключением, когда вам нужно запустить Selenoid без Docker. Но это уже совсем другая история.
В статье на своем опыте я расскажу и покажу с какими сложностями сталкивался и как их решал. Хотелось бы подчеркнуть, что возможно у вас возникнут подобные проблемы при установке и настройке данного инструмента.
Установка и настройка Selenoid
Чтобы начать установку и настройку Selenoid, нужно сперва установить Docker. Для этого идём на официальный сайт, выбираем свою ОС и устанавливаем программу.
Чтобы удобно было управлять Selenoid, сразу устанавливаем docker-compose. Это решение, которое позволяет описать настройки для нескольких Docker контейнеров в одном yaml файле и упралять ими.
Для этого нужно перейти на сайт и скачать в директорию /usr/local/bin последний доступный релиз.
cd /usr/local/bin/
sudo wget https://github.com/docker/compose/releases/download/v2.21.0/docker-compose-linux-x86_64
Переименовываем файл.
sudo mv docker-compose-linux-x86_64 docker-compose
И даём права на запуск.
sudo chmod +x docker-compose
Теперь нам нужно создать docker-compose.yml файл для docker-compose. У нас он получился вот таким.
version: "3"
services:
selenoid:
image: aerokube/selenoid:latest-release
container_name: selenoid
network_mode: bridge
ports:
- "4444:4444"
environment:
- "OVERRIDE_VIDEO_OUTPUT_DIR=$PWD/video"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
- "/etc/selenoid:/etc/selenoid"
- "./video:/opt/selenoid/video"
- "/opt/selenoid/logs:/opt/selenoid/logs"
command: ["-conf", "/etc/selenoid/browsers.json", "-limit", "20", "-retry-count", "1000", "-video-output-dir", "/opt/selenoid/video", "-log-output-dir", "/opt/selenoid/logs", "-max-timeout", "20m0s", "-session-attempt-timeout", "15m", "-timeout", "10m", "-service-startup-timeout", "10m"]
selenoid-ui:
image: aerokube/selenoid-ui:latest-release
container_name: selenoid-ui
network_mode: bridge
ports:
- "8080:8080"
links:
- selenoid
command: -selenoid-uri 'http://selenoid:4444'
depends_on:
- selenoid
Здесь важно понимать, что без yaml файла docker-compose работать не будет.
Далее нам нужно создать и настроить конфигурационный файл /etc/selenoid/browsers.json.
{
"android": {
"default": "10.0",
"versions": {
"10.0": {
"image": "selenoid/android:10.0",
"port": "4444",
"path": "/wd/hub",
"env": [
"VERBOSE=true",
"APPIUM_ARGS=--log-level debug"
],
"selenoid:options": {
"enableVNC": "true",
"enableLog": "true",
"enableVideo": "true"
}
}
}
}
}
После всей подготовки запускаем Selenoid. Для этого переходим в директорию, где у вас лежит подготовленный ранее файл docker-compose.yml и выполняем команду
docker-compose up -d
После этого скачаются образы selenoid и selenoid-ui и запустятся контейнеры.
Проверяем, что selenoid и его ui запущен
docker-compose ps -a
Up <time> говорит о том, что контейнеры запущены и работают
Теперь идем в браузер и открываем ui selenoid, чтобы точно убедиться, что все заработало. http://<hostname>:8080.
Две зеленые надписи CONNECTED говорят о том, что все хорошо. Но тесты запускать пока рано. Переходим на сайт с образами для Android и скачиваем образ с Android 10.
docker pull selenoid/android:10.0
Запуск тестов и пара проблем
Мы установили Selenoid, скачали образ с Android 10, теперь можно приступать к тестированию.
Мы используем стек:
Gradle.
Java.
JUnit5.
Appium.
С разбегу запустить тесты на Selenoid не получилось. При первом запуске получили вот такую ошибку.
Этот лог нам ничего не сказал. Лезем в логи контейнера с Android-эмулятором.
Здесь уже поинтересней. Оказалось, что на ПК выключена виртуализация.
Заходим в BIOS и включаем виртуализацию. У каждого производителя виртуализация включается по разному.
Далее столкнулись с другой проблемой. При запуске тестов с таким capability...
final DesiredCapabilities device = new DesiredCapabilities();
device.setCapability("deviceName", "android");
device.setCapability("version", "10.0");
device.setCapability("appPackage", "ru.app.mobile.android");
device.setCapability("appActivity", "ru.app.mobile.android.splash.presentation.activity.SplashActivity");
device.setCapability("enableVNC", true);
device.setCapability("enableLog", true);
device.setCapability("enableVideo", true); // Uncomment this to record video
driver = new AppiumDriver<>(new URL(
"http://<selenoid>:4444/wd/hub" //Replace with correct host and port
), device);
...получали такую ошибку.
.
java
org.openqa.selenium.SessionNotCreatedException: Unable to create a new remote session. Please check the server log for more details. Original error: All non-standard capabilities should have a vendor prefix. The following capabilities did not have one: enableLog,enableVNC,enableVideo,version
Build info: version: '3.141.59', revision: 'e82be7d358', time: '2018-11-14T08:17:03'
System info: host: 'MacBook-Pro-Pavel.local', ip: 'fe80:0:0:0:14d7:d36:4180:ab86%en0', os.name: 'Mac OS X', os.arch: 'aarch64', os.version: '13.5.1', java.version: '11.0.20'
Driver info: driver.version: AppiumDriver
remote stacktrace: InvalidArgumentError: All non-standard capabilities should have a vendor prefix. The following capabilities did not have one: enableLog,enableVNC,enableVideo,version
После общения в чате поддержки, оказалось, что capability должен выглядеть примерно вот так.
DesiredCapabilities device = new DesiredCapabilities();
device.setCapability("appium:deviceName", "android");
device.setCapability("appium:version", "10.0");
device.setCapability("appium:app", "ru.app.mobile.android");
device.setCapability("appium:appPackage", "ru.app.mobile.android.feature");
device.setCapability("appium:sessionTimeout", "15m");
device.setCapability("appium:enableVNC", true);
device.setCapability("appium:enableLog", true);
device.setCapability("appium:enableVideo", true); // Uncomment this to record video
device.setCapability(NEW_COMMAND_TIMEOUT, "3000");
AppiumDriver<RemoteWebElement> driver = new AndroidDriver<>(new URL(
"http://<selenoid>:4444/wd/hub" //Replace with correct host and port
), device);
Но при таком capability в selenoid-ui были видны только логи appium, без VNC.
Оказалось, что enableVNC нужно запускать по другому.
Map<String, Object> selenoidOptions = Map.of("enableVNC", true,
"enableLog", true,
"enableVideo", true);
DesiredCapabilities device = new DesiredCapabilities();
device.setCapability("appium:deviceName", BrowserType.ANDROID);
device.setCapability("appium:platform", Platform.ANDROID);
device.setCapability("appium:version", "10.0");
device.setCapability("appium:app", "ru.app.mobile.android.feature");
device.setCapability("appium:appPackage", "ru.alfabank.mobile.android.feature");
device.setCapability("appium:appActivity", "ru.alfabank.mobile.android.splash.presentation.activity.SplashActivity");
device.setCapability("appium:sessionTimeout", "15m");
device.setCapability("selenoid:options", selenoidOptions);
device.setCapability(NEW_COMMAND_TIMEOUT, "3000");
AppiumDriver<RemoteWebElement> driver = new AndroidDriver<>(new URL(
"http://<selenoid>:4444/wd/hub" //Replace with correct host and port
), device);
driver.manage().timeouts().implicitlyWait(launchPropertyProvider.getImplicitWaitDuration(), TimeUnit.SECONDS);
return driver;
Вот теперь можно запускать тесты или приступать к сборке собственного образа с Android эмулятором.
Сборка собственного образа с Android эмулятором
Клонируем репозиторий.
git clone https://github.com/aerokube/images
Переходим в директорию selenium и запускаем скрипт automate_android.sh.
cd selenium
./automate_android.sh
Вводим последнею стабильную версию appium, либо оставляем версию по умолчанию.
Specify Appium version: [2.0.1] 2.1.3
Далее выбираем какой тип Android будем использовать: выбираем с Google сервисами (google_apis_playstore) или без (google_apis).
Specify Android image type (possible values: "default", "google_apis", "google_apis_playstore", "android-tv", "android-wear"): [default] google_apis_playstore
Следующим пунктом выбираем, какой интерфейс приложения будет использоваться.
Specify Application Binary Interface (possible values: "armeabi-v7a", "arm64-v8a", "x86", "x86_64"): [x86] x86_64
Далее выбираем версию Android — доступны версии с 4 по 14. В примере ниже выбрал версию 12.0.
Specify Android version: [8.1] 12.0
Идем в Android Studio, смотрим список доступных эмуляторов...
...и вводим нужное название эмулятора...
Specify device preset name if needed (e.g. "Nexus 4"): Pixel 6a
...или оставляем значение по умолчанию.
Далее выбираем объем SD карты для эмулятора, оставляем по умолчанию 500 Mb или указываем свое значение.
Specify SD card size, Mb: [500]
Следующим шагом указываем объем памяти для эмулятора, оставляем значение по умолчанию или указываем свое значение.
Specify userdata.img size, Mb: [500]
Следующим шагом указываем нужно ли устанавливать Chrome для web тестирования на Android, оставляем значение по умолчанию.
Are you building a Chrome Mobile image (for mobile web testing): [n]
Указываем версию Chromedriver. Оставляем значение по умолчанию.
Specify Chromedriver version if needed (required for Chrome Mobile):
Как будет называться наш docker образ? Оставляем по умолчанию или задаем свое имя.
Specify image tag: [selenoid/android:12.0]
И, наконец, нас спрашивают «Добавить ли снимок быстрой загрузки». Оставляем значение по умолчанию.
Add Android quick boot snapshot? [y]
После начнется сборка образа с заданными параметрами.
Когда сборка закончится, проверяем, наш новый образ.
Теперь нам нужно добавить образ в конфигурацию selenoid. Для этого открываем и правим файл /etc/selenoid/browsers.json.
{
"android": {
"default": "12.0",
"versions": {
"10.0": {
"image": "selenoid/android:10.0",
"port": "4444",
"path": "/wd/hub",
"env": [
"VERBOSE=true",
"APPIUM_ARGS=--log-level debug"
],
"selenoid:options": {
"enableVNC": "true",
"enableLog": "true",
"enableVideo": "true"
}
},
"12.0": {
"image": "selenoid/android:12.0",
"port": "4444",
"path": "/wd/hub",
"env": [
"VERBOSE=true",
"APPIUM_ARGS=--log-level debug"
],
"selenoid:options": {
"enableVNC": "true",
"enableLog": "true",
"enableVideo": "true"
}
}
}
}
}
Перезапускам Selenoid, чтобы изменения подхватились.
docker-compose down && docker-compose up -d
Итог
Изначально я планировал разместить этот материал только для внутреннего использования в Confluence, чтобы делиться материалом по теме. Но по мере написания статьи, все больше понимал, что мой опыт может помочь не только мне и моим коллегам, но и остальным. Поэтому я искренне надеюсь, что здесь вы найдете решение основных проблем, с которыми я столкнулся. А сэкономленное время вы сможете потратить на погружение в прекрасный мир тестирования или другие приятные вещи. Желаю, чтобы у вас все получилось!
Selenoid хороший инструмент. Например, нам он дал нам следующее:
возможность сразу запускать тесты, без необходимости настраивать тестовую среду локально;
паралелльный запуск тестов, без необходимости дополнительной настройки тестовой среды;
тестирование на всех версиях Android и всех доступных эмуляторах;
удобный web интерфейс и мониторинг процесса тестирования;
запись видео тестирования.
Также в планах есть интеграция Appium Inspector с Selenoid, чтобы коллегам было еще удобнее писать тесты, без необходимости поднимать и настраивать локально тестовую среду.
Комментарии (2)
Pecnikas
15.11.2023 08:28+1Крайне понятная статья, сейчас тоже поднимаем подобную инфраструктуру, подскажите а каким образом можно подключить к этому делу внешнюю ноду ? имею в виду если я хочу чтобы селеноид был на 1м физической машине, а эмуляторы на другой, ну или если я захочу добавить еще 1 машину ?
pbezpal Автор
@Pecnikas если вы захотите использовать ещё одну машинку, то для этого вам нужно будет расспаралелливать при помощи ggr от этих же ребят, вот дока https://aerokube.com/ggr/latest/
По поводу использования эмуляторов на отдельной машинке не подскажу, потому что мы это решение не прорабатывали. Но вы можете спросить в поддержке https://t.me/aerokube