Тестирование selenium: Нагрузочное тестирование с помощью Selenium / Хабр
Клиентские тесты на Lettuce + Selenium / Хабр
Введение
На данный момент самым популярным решением для клиентского тестирования является selenium. Стоит заметить, что вполне заслужено — те возможности, которые предоставляет selenium в связке с webdriver’ом, действительно охватывают почти весь спектр пользовательского взаимодействия с веб-приложениями.
Для небольших проектов замечательно подходит вариант с плагинами для браузеров, функционал которых можно расширить добавлением сторонних компонентов (например, UI-element). Но когда проект становится достаточно большим, а многие его части многократно изменяются и даже полностью перепиливаются, после каждого изменения в структуре страницы или способе подачи данных приходится заменять сразу целые блоки тестов, заглядывая чуть ли не в каждый тест. После такого selenium плагины уже перестают казаться столь удобными. И тут на помощь приходят библиотеки selenium, реализованные для многих языков ассоциируемых с веб-разработкой (документация на официальном сайте)
Предлагаю вам посмотреть на возможности клиентского тестирования (в частности django проектов), которые дает python-selenium в связке с библиотекой lettuce.
Lettuce + Selenium
Давайте посмотрим на те возможности, которые предоставляют эти компоненты по отдельности:
Python-Selenium
- как было сказано выше, selenium имеет богатый арсенал взаимодествия с веб-приложениями через браузер
- в отличие от плагинов есть возможность использовать обширный функционал python’а
- интеграция с самим проектом
Lettuce
- разделение тестов на слабосвязанные части
- контроль над каждой стадией тестирования
- красивый output в терминале 🙂
И сразу в бой
На примере простых тестов регистрации и авторизации я постараюсь продемонстрировать основные аспекты работы с lettuce + selenium.
Постановка задачи
Нужно создать 2 теста, которые будут выполнять следущие действия:
Регистрация:
- Зайти на страницу регистрации
- Заполнить поля в форме регистрации
- Нажать на кнопку регистрации
- Увидеть сообщение о успешной регистрации
Авторизация:
- Зайти на страницу авторизации
- Заполнить поля в форме авторизации
- Нажать на кнопку авторизации
- Увидеть сообщение о успешной авторизации
Уже из постановки задачи видно, что эти 2 теста выполняют схожие действия, но в разном контексте. Приступим к выполнению задачи.
Выполнение задачи
Добавив lettuce в наш django проект, как это описано в официальной документации, и установив все необходимые зависимости (в нашем случае это системные пакеты firefox и питонвские модули lettuce и selenium) можно приступать к написанию тестов.
P.S.: для запуска в режиме headless вам пригодятся xvfb и pyvirtualdisplay
Для работы с lettuce необходимо создать следущие файлы:
- terrain.py в корне проекта содержит инструкции, выполняемые на указанной стадии тестирования
- *.feature файлы в папке myapp/features содержит пошаговое описание каждого теста
- *.py файлы в папке myapp/features содержат описания шагов, используемых в *.feature файлах
От себя могу посоветовать включить в проект файл, содержащий структуру страниц вашего приложения (по аналогии с PageObject, используемым в selenium). Назовем этот файл mapping.py и положим в корень проекта. Данное отделение структуры страниц от тестов снижает потребность в переписывании самих тестов при изменении верстки: достаточно поправить соответствующую страницу в mapping.py. Так же это существенно увеличивает читаемость тестов (дальше это будет наглядно показано).
mapping.py
host_url = 'http://example.com'
site_mapping = {
"registration": {
"url": host_url + "/registration/",
"username": "//input[@id='username']",
"email": "//input[@id='email']",
"password": "//input[@name='password1']",
"verify password": "//input[@name='password2']",
"signup button": "//button[@name='signup']",
"status message": "//div[@id='status']",
},
"authorization": {
"url": host_url + "/login/",
"username": "//input[@id='username']",
"password": "//input[@name='password']",
"login button": "//button[@name='login']",
"status message": "//div[@id='status']",
},
}
P.S.: Я использую xpath, т.к. считаю это самым оптимальным способом поиска элементов
terrain.py
from lettuce import before, after, world
from selenium import webdriver
from mapping import site_mapping
@before.harvest
def setup(server):
# world - переменная, используемая lettuce между всеми стадиями тестов, т.е. хранящая в себе информацию между тестами
world.browser = webdriver.Firefox() # открываем браузер
world.mapping = site_mapping # сохраняем структуру в world
@after.all
def teardown(total):
world.browser.close() # закрываем браузер
myapp/features/auth.feature
Feature: Authorization
Scenario: Registration
Open "registration" page
Fill "username" with "myusername"
Fill "email" with "[email protected]"
Fill "password" with "1234"
Fill "verify password" with "1234"
Click "signup button"
See "Welcome aboard" in "status message"
Scenario: Authorization
Open "authorization" page
Fill "username" with "myusername"
Fill "password" with "1234"
Click "login button"
See "Hello! Again..." in "status message"
Как вы видите, отсутствие информации о расположении элементов сыграло роль на читаемости сценариев. Спасибо mapping.py за это
myapp/features/steps.py
from lettuce import step, world
@step(r'Open "(.*)" page')
def open_page(step, page):
world.current_page = world.mapping[page] # взять url искомой страницы
world.browser.get(world.current_page['url']) # открыть этот url в браузере
@step(r'Fill "(.*)" with "(.*)"')
def fill_element_with_text(step, element, value):
elem = world.browser.find_element_by_xpath(world.current_page[element])
elem.send_keys(value)
@step(r'Click "(.*)"')
def i_click_xpath(step, element):
elem = world.browser.find_element_by_xpath(world.current_page[element])
elem.click()
@step(r'See "(.*)" in "(.*)"')
def i_see_text_in_element(step, text, element):
elem = world.browser.find_element_by_xpath(world.current_page[element])
assert elem.text == text
Вот и все. Осталось только запустить тесты и смотреть, как они успешно (или не очень) проходят.
Кажется, что слишком много телодвижений для написания каких-то двух тестов — так и есть. Но если вы хотите покрыть проект большим количеством тестов, то по мере написания сценариев и шагов к ним, вам все меньше будет необходимо писать новые шаги, т.к. почти все возможное взаимодействие пользователя с вашим сайтом уже будет описано в существующих шагах — останется только писать новые сценарии, что не сложнее, чем было написать пункт «постановка задачи» чуть выше.
Итог
Что имеем в остатке:
- Инструмент, которым могут пользоваться как разработчики, так и тестировщики.
- Высокая устойчивость к изменениям в верстке и структуре сайта в целом благодоря mapping.py
- Можно запускать тесты практически в чем угодно. Firefox, chrome, phantomjs (возможно есть и другие варианты, но это то, что пробовал я).
- Запускать тесты где угодно: на своем компьютере, на виартуальной машине, на удаленном сервере
- Для каждого прогона тестов можно создавать тестовую базу данных, включать отдельный инстанс вашего приложения, подгружать тестовые данные, а по окончании все это благополучно удалять (как это делает тестовый фреймворк в самом django).
- Можно прицепить сохранение логов. А если к этому приурочить асинхронные таски, то можно каждые N часов получать информацию о состоянии всего проекта.
- При большой базе шагов (steps.py) достаточно будет описывать только сценарии, которые довольно просто писать «переводя» в них ТЗ.
- Развернув такие тесты на одном проекте не составит большого труда перенести их на другой проект. При переносе на новый проект больше всего времени займет написание сценариев, что не кажется таким уж сложным (по сравнению, например, с созданием очередной сотни тестов в плагинах selenium)
Полезные ссылки по теме:
P.S.: Надеюсь, что кто-нибудь заинтересуется этой темой и будет резонно написать про подводные камни, с которыми я столкнулся, используя lettuce + selenium. Буду рад ответить на ваши вопросы.
P.P.S: Заранее извиняюсь за стиль изложения, пунктуацию и вообще. Первая статья и все такое…
Автоматизация приемочного тестирования Selenium + .NET Web Api + AngularJs / Хабр
Я расскажу как мы в компании работаем с приемочными тестами. В статье вас ждет ссылка на репозиторий с кодом и видео с примером работы.
Не все тесты одинаково полезны
Некоторое время назад был актуален спор — «Должен ли разработчик тестировать свой код?». Да, разработчик должен тестировать то что он создает. Думаю, что сейчас с этим утверждением мало кто поспорит.
Следующий вопрос был — «Каким образом разработчик должен тестировать свой код?». Ответ на это вопрос был найден — TDD. В идеальном мире разработчик большую часть функционала разрабатывает через тесты. В качестве результата получаем хороший дизайн кода, который удобно поддерживать и модифицировать, плюс набор тест-кейсов, которые позволяют разработчику со спокойной душой вносить изменения в существующий код.
Это происходит в идеальном мире. По факту не всегда получается всю разработку выполнять через тестирование. Даже если вся разработка выполняется при помощи TDD, то мы все равно не можем сказать, что разрабатываемая система при запуске у заказчика будет исправно работать.
Модульные тесты не затрагивают окружающую среду — если надо протестировать сервис который обращается в БД за данными, то разработчик пишет заглушку для БД. Если надо проверить сервис, который обращается к внешней службе, то разработчик пишет заглушку, которая эмулирует работу этой службы.
Следующим этапом появляются конфигурационные и интеграционные тесты, которые вносят в виртуальную тестовую среду физические элементы системы — сервера БД, аппаратные межсетевые экраны, стороннее программное обеспечение. Реализация таких тестов позволяет нам сказать, что система «правильно» взаимодействует с окружением. Но даже «правильное» взаимодействие с окружением не гарантирует нам, что в итоге система будет работать ожидаемо — по сценариям, которые описаны в спецификации.
Как показывает моя практика — самым полезным тестированием является приемочное тестирование. Под приемочным тестированием я понимаю следующее:
- Создана тестовая площадка максимально приближенная к конфигурации продакшена
- Тестовая площадка включает в себя аппаратную и программную составляющую — межсетевые экраны, сервера, стороннее ПО и т.д.
- На данной площадке выполняются тесты по сценариям, которые прописаны в приемочной методике испытания системы(здравствуй ГОСТ 34)
- На площадке проверяются основные кейсы по которым пользователь работает с системой
Если удается поднять такую площадку(что зачастую бывает сделать сложно), и проверить все тест-кейсы по сценариям спецификаций, то с большой вероятностью можно сказать, что система работает ожидаемо и как следствие — не содержит ошибок.
Ошибки конечно будут, но выполнение приемочного тестирования позволяет с большей вероятностью (по сравнению с модульным и интеграционным тестированием) обнаружить ошибки.
Автоматизируем приемочное тестирование
Автоматизация приемочного тестирования сводится к следующим шагам:
- Написать сценарии приемочных тестов
- Разработать тесты на основе Selenium
- Автоматизировать процесс запуска тестов на исполнение после изменения кода в репозитории
Сценарии приемочных тестов
Мы записываем сценарии приемочных тестов в виде use case сценариев в спецификациях. Спецификации разрабатывает аналитик на основе функциональных, пользовательских, нефункциональных и других требований.
Для ведения спецификаций мы используем Atlassian Confluence в связке с Balsamiq Mockups.
Разработка тестов на основе Selenium
Для разработки тестов мы создали собственное решение, которое позволяет:
- Разрабатывать тесты на основе паттерна PageObject
- Запускать тесты на различных браузерах
- В случае ошибки теста получать скриншот, копию html страниц и название тест-кейса
Разработка новых тестов сводится к описанию тестируемой страниц — PageObject и разработке шагов тест-кейса.
Проект с приемочными тестами выглядит так:
Основные компоненты:
- Common\BasePage.cs — базовый классы для описания PageObject страниц. Содержит вспомогательные методы поиска элементов на странице при помощи различных селекторов.
- Common\BaseTest.cs — базовый класс для всех приемочных тестов. Содержит логику запуска/останова браузеров для выполнения тестов, логику ожидания завершения всех активных $http запросов клиентского приложения.
- PageObjects — директория содержит описание страниц клиентского приложения. Сраница Page Object инкапсулирует в себе знания о элементах страницы и о действиях, которые можно выполнить на странице.
- Директория TestCases — содержит кейсы для выполнения тестов
Тест состоит из шагов — Step(). Шаг может выполнить действие и проверить выполнение некоторого утверждения. Ниже приведен пример теста:
- Открыть страницу авторизации
- Войти как администратор
- Открыть отчет
- Заблокировать отчет
- Отредактировать две ячейки «110» и «220»
- Сохранить изменения
- Снять блокировку с отчета
- Убедиться, что в ячейке «ГОУ» рассчиталась сумма по введенным значениям — «110» + «220»
Код теста:
На видео показана работа теста.
Если во время теста произошла ошибка — авторизация не прошла, не открылся отчет и т.д., то в директорию, указанную в app.config, будет сохранен скриншот страницы, название браузера, название теста и html страница с ошибкой.
Определение завершения всех $http запросов AngularJS приложения
Клиентское SPA приложение выполняет запросы к серверу при помощи сервиса $http. Например, при открытии отчета «Суточная ведомость» выполняется асинхронное обращение к серверу. В ответ клиент получает от сервера данные по отчету.
В тестовых сценариях необходимо уметь дождаться завершения всех запросов. Например, клиентскому приложению после перехода к отчету требуется время чтобы загрузить данные с сервера. После того как данные загружены и отображены на странице следует проводить тестирование данной страницы.
Для отслеживания завершения всех $http запросов я использую следующий подход:
- В клиентском приложении создается переменная, которая содержит число активных $http запросов
- В сервис $http производится инъекция, которая увеличивает переменную на 1 при отправке запроса и уменьшает переменную на 1 при успешном или неуспешном завершении запроса
- Selenium проверяет значение этой переменной, чтобы убедиться, что клиент завершил обработку запроса
Запуск приемочных тестов при помощи TeamCity
В качестве сервера непрерывной интеграции мы используем TeamCity.
После того как разработчик отправил код в репозиторий — TeamCity развертывает тестовую площадку и запускает на ней приемочные тесты. Таким образом, после каждого изменения кода происходит установка и тестирование проекта с нуля. Это решение очень экономит время плюс позволяет нам не думать о регрессионном тестировании.
Основные шаги:
- Очистить директорию сайта от старой сборки
- Настроить app.config приложения — выполняется конфигурация строк соединения с тестовой БД
- Собрать проект — запуск MSBuild
- Остановить IIS
- Удалить старую тестовую БД
- Создать новую тестовую БД
- Скопировать файлы приложения в директорию сайта
- Запустить IIS
- Запустить приемочные тесты
Кто пишет приемочные тесты
Приемочные тесты может писать как разработчик — по завершению реализации сценария, так и специально выделенный на данные задачи инженер-тестировщик.
Исходный код
Исходный код тестового приложения доступен на github.
Вывод
Автоматизировать приемочное тестирование можно и нужно. Плюсы данного подхода:
- Есть гарантии, что в репозитории находится рабочий код, который обязательно соберется, установится на площадку и будет исправно работать по сценариям спецификаций
- Сокращается время на ручное тестирование — тест пишется один раз и исполняется при каждом изменении кода
- Сокращается время на регрессионное тестирование
- Сокращается время на поиск и документирование ошибок — если тест не прошел, то в логах будут записаны шаги воспроизведения и приложен скриншот
- Сокращается стоимость исправления ошибок — ошибка найденная в офисе будет стоить дешевле ошибки найденной у заказчика
В завершении статьи скажу, что для больших и долгих проектов, которые длятся половину года и более — наличие автоматизированных приемочных тестов является необходимым условием для обеспечения требуемого качества продукта.
Тестирование Django приложений с помощью Selenium / Хабр
Selenium
Selenium — это очень удобный (имхо) инструмент для тестирования веб-приложений.
Тесты создаются с помощью дополнения для Firefox, которое может генерировать код теста на различных языках, в том числе и на Python. Затем эти тесты выполняются специальным сервером, Selenium RC.
Сам по себе Selenium не привязан ни к языкам ни к фреймворкам, поэтому чтобы интегрировать его в систему тестирования Django-приложений, нужно приложить очень небольшие усилия.
Для решения задачи интеграции я буду использовать библиотеку Django: Sane Testing. Это библиотека, расширяющая возможности стандартной системы тестирования Django, в том числе и поддержкой тестов Selenium.
Ставим Django: Sane Testing
Установка этой библиотеки была бы стандартной, если бы она не тянула за собой Django. Что не есть правильно, если вы пользуетесь транком, как и я.
Скачиваем актуальный релиз, распаковываем (можно в /tmp), открываем setup.py, находим
install_requires = ['Django>=1.0_final','nose>=0.10'], <br/>
либо удаляем, либо комментим часть про Django. После этого ставим:
sudo python setup.py install
Ставим Selenium
Нужно поставить сервер и плагин для Firefox. И то, и другое находится на странице загрузки.
Для установки плагина достаточно открыть ссылку Selenium IDE, разрешить установку плагина, установить его и перезапустить Firefox. Кроме того, уважаемый bazzzman написал расширение для этого плагина (!), для удобства работы.
Для установки сервера нужно скачать архив по ссылке Selenium RC, распаковать его куда-нибудь. В получившемся после распаковки каталоге будет несколько подкаталогов. Среди них будет selenium-server-x.y.z, это каталог с сервером. Сам сервер — это файл selenium-server.jar. Вот его куда-нибудь копируем, в удобное место, например в /usr/local/lib, после чего весь распакованный каталог можно потереть, он больше не нужен.
Для удобного запуска создаём скрипт,
sudo nano /usr/local/bin/selenium-server
с таким содержимым:
#!/bin/bash
/usr/bin/env java -jar /usr/local/lib/selenium-server.jar
Задаём ему права на выполнение:
sudo chmod 755 /usr/local/bin/selenium-server
Проверим: после выполнения команды /usr/local/bin/selenium-server должно появляться что-то эдакое:
23:58:17.788 INFO - Java: Sun Microsystems Inc. 14.2-b01
23:58:17.798 INFO - OS: Linux 2.6.31-14-generic i386
23:58:17.863 INFO - v1.0.1 [2696], with Core v@VERSION@ [@REVISION@]
23:58:18.111 INFO - Version Jetty/5.1.x
23:58:18.113 INFO - Started HttpContext[/selenium-server/driver,/selenium-server/driver]
23:58:18.114 INFO - Started HttpContext[/selenium-server,/selenium-server]
23:58:18.114 INFO - Started HttpContext[/,/]
23:58:18.166 INFO - Started SocketListener on 0.0.0.0:4444
23:58:18.166 INFO - Started org.mortbay.jetty.Server@fc9944
если так и есть, значит сервер работает ОК.
Тестовый проект
Создаём тестовый проект:
django-admin.py startproject justtotest
В проекте будет одно приложение, назовём его habrahabr:
./manage.py startapp habrahabr
Наш тестовый хабр будет состоять из одной модели:
class Greeting(models.Model):
text = models.CharField(max_length=200)
одной формы для ввода приветствия:
class GreetingForm(forms.ModelForm):
text = forms.CharField(widget=forms.TextInput(attrs={‘size’:’40’}),
error_messages={‘required’: ‘А текст приветствия ввести ? ‘})
class Meta:
model = Greeting
и одной вьюшки:
def Greetings(request):
template_name = ‘habrahabr/index.html’
title=’Selenium’
if request.method == ‘GET’:
form = GreetingForm()
else:
form = GreetingForm(request.POST)
if form.is_valid():
text = form.cleaned_data[‘text’]
new_greeting=Greeting(text=text)
new_greeting.save()
return HttpResponseRedirect(‘/’)
greetings = Greeting.objects.all().order_by(‘-id’)
context = {
‘title’: title,
‘greetings’: greetings,
‘form’: form,
}
return render_to_response(template_name, context,
context_instance=RequestContext(request))
на которой выводится список добавленных ранее приветствий и форма для добавления нового приветствия.
Создание теста Selenium
Запустим проект и в браузере создадим тест с помощью плагина, смотрите на видео (советую смотреть в HQ):
Как видите, у нас получился код на питоне. Из этого сгенерированного кода возьмём файл класса и немножко доработаем его, чтобы в нашем tests.py получилось вот такое:
# coding: utf-8
from djangosanetesting.selenium.driver import selenium
import unittest, time, re
class Untitled(unittest.TestCase):
test_type = «selenium»
start_live_server = True
def setUp(self):
self.start_live_server=True
self.verificationErrors = []
self.selenium = selenium(«localhost», 4444, «*chrome», «127.0.0.1:8000/»)
self.selenium.start()
def test_required_text_exists(self):
sel = self.selenium
sel.open(«/»)
sel.type(«id_text», «Testing with Selenium»)
sel.click(u»//input[@value=’Добавить’]»)
sel.wait_for_page_to_load(«30000»)
try: self.failUnless(sel.is_text_present(«Testing with Selenium»))
except AssertionError, e: self.verificationErrors.append(str(e))
def tearDown(self):
self.selenium.stop()
self.assertEqual([], self.verificationErrors)
if __name__ == «__main__»:
unittest.main()
В класс мы добавили два атрибута. test_type
— указывает на тип теста и start_live_server
— он говорит о том, что нужно будет запускать тестовый сервер.
Кроме того, импорты другие, после установки sane у нас уже всё есть в установленном пакете.
Скрипты для запуска тестов
Есть два варианта настроек для запуска тестов. Первый вариант — добавить в settings.py переменную TEST_RUNNER
, но в этом случае не получится выбирать индивидуальные типы тестов, например, только юнит-тесты, или только селениум-тесты, а ведь не всегда нужно запускать все.
Поэтому я выбрал второй вариант — написал скрипты для запуска тестов. Первый скрипт, nose-selenium:
#!/bin/bash
DJANGO_SETTINGS_MODULE=«settings» PYTHONPATH=».:..» nosetests —with-django —with-djangoliveserver —with-sanetestselection —select-seleniumtests;
этот скрипт запустит селениум-тесты с тестовым сервером.
Второй скрипт, nose-unittests:
#!/bin/bash
DJANGO_SETTINGS_MODULE=«settings» PYTHONPATH=».:..» nosetests —with-django —with-sanetestselection —select-unittests;
этот скрипт запустит юнит-тесты, без тестового сервера.
Можно сделать необходимые скрипты на все случаи жизни, все типы тестов перечислены в документации. Не забудьте установить права на выполнение скриптов, chmod 755
.
Запуск тестов
Теперь всё готово для запуска тестов. Необходимо стартануть сервер Selenium, /usr/local/bin/selenium-server, после чего можно запускать тесты с помощью скриптов.
Я не стал делать скринкаст, но будьте уверены, что всё работает ОК — запускается браузер, контачит с сервером, заполняет форму, проверяет наличие текста, результаты выводятся как обычно.
Код к статье выложил на яндексе, если файл оттуда исчезнет, пишите в личку.
Резюме
На мой взгляд, селениум является хорошим дополнением к системе тестов, т.к. позволяет тестить javascript-насыщенные интерфейсы, что стандартной системе тестов не под силу. Кроме того, сама по себе Django: Sane Testing предлагает дополнительные фичи, о которых я вам советую прочесть в документации.
Надеюсь, моя статья будет полезной для широкого круга Django-разработчиков, как начинающих, так и опытных. От опытных разработчиков жду комментов по теме 🙂
P.S.
Windmill не пробовал. Если она проще\лучше\надёжнее, чем Selenium, пожалуйста опишите в комментах или в виде статьи. Линк на статью помещу в начало этой.
Кому еще нужен Selenium? Использует ли кто BDD в 2020? Машинное обучение в Selenium
Каждый раз, когда натыкаюсь на новую статью про то, как использовать BDD-подход и как он улучшает жизнь разработки, тестирования и менеджмента — я хватаюсь за лицо. (А сейчас не знаю как быть. Не хватаюсь за лицо, а просто грущу). Впрочем, такие же ощущения могут вызывать задачи по написанию Selenium тестов. Захотелось поговорить об этом с теми, кто сталкивается с Selenium тестами и разрабатывает различные инструменты для удобной работы с ними.
Мы (Всеволод Брекелов и Дарья Манухина, программный комитет конференции Heisenbug) пообщались с Анной Чернышовой, разработчиком библиотеки Akita и нового инструмента Healenium (ее доклад про BDD), и Иваном Крутовым, разработчиком Selenoid. Иван занимается инфраструктурой для Selenium тестов не первый год (Один из его мастер классов). Обсудили:
- BDD подход в 2020;
- Selenium и его развитие;
- Карьерный рост;
- Машинное обучение и Selenium.
Интервью состоит из двух частей: во второй поговорили про инфраструктуру Selenium-тестов, инструментарий тестировщика и ответили на вопрос, который прозвучал в конце этого поста.
Много букв про собеседников
— Аня, Ваня, расскажите о себе. Начнем с Ани: расскажи вкратце чем в основном занимаешься.
Аня: У меня сейчас две основные активности: первая — я в EPAM работаю в центре компетенций по тестированию. Это такая группа людей, к которым обращаются за консультациями, за помощью в старте проекта, подборе технологий. Много занимаюсь аудитом тестирования на проектах. Я разбираюсь что не так, что хорошо, что плохо, рекомендую улучшения, делаю PoC. В основном такой консалтинг внутри компании. Второе направление — это акселератор, наш новый Healenium, мы его заопенсорсили относительно недавно, это штука, которая умеет чинить в рантайме поломанные локаторы и держать тесты в актуальном состоянии.
— Здорово! Ваня, а ты? Я знаю, что ты разработчик Selenoid.
Ваня: Я по специализации разработчик. Java, Go — в основном такие вот языки. Хотя начинал сто лет назад. Писал ещё на PHP, когда самое простое было там. В школе писал на всяких паскалях, как и все. В итоге последние лет 6 я занимаюсь тем, что сейчас называется модным словом DevOps, это такая штука на стыке. По должности на русском языке это может называться, например, инженер-программист, это одновременно и разработчик, и человек, который занимается поддержанием инфраструктуры. Например, я отвечаю за работоспособность большого кластера Selenium с достаточно большим количеством браузеров, он отказоустойчивый, распределённый и так далее. Это первая часть. Вторая часть — я занимаюсь всякими опенсорсными и не только проектами. Мы пишем Selenoid, небезызвестный всем в опенсорсе. Также у нас есть коммерческие инструменты. Например, Selenium для Kubernetes — это отдельный продукт, делаем облачные решения для Selenium, ну и многое другое. Есть ещё продуктовое направление, профессионально разрабатываем инструменты для Selenium: открытые и закрытые — разные. Такая деятельность. По конференциям, естественно, езжу, выступаю, просвещаю людей, как эффективно строить Selenium на основе имеющегося у меня опыта.
— Ты сказал немного про Selenoid. Я знаю, что Selenoid — это проект организации Aerokube. Можешь рассказать как это? Это сообщество или это организация? Коммерческая организация или как это вообще появилось?
Ваня: Это и то и другое. На самом деле изначально это было просто сообщество, завели организацию фактически на GitHub для того, чтобы делать опенсорсные эффективные инструменты для Selenium. Это делалось в свободное от работы время, от основной работы. Получилось сделать первый инструмент Selenoid, потом в итоге мы поняли, что для того чтобы иметь возможность нормально обеспечивать, так сказать, эффективную разработку этого Selenoid нужно одно из двух.
Все хорошие опенсорсные продукты развиваются по одному из двух направлений. Первое — когда они делаются в какой-то крупной компании, которая их просто спонсирует, платит зарплату разработчикам, а второй вариант — когда есть бесплатное опенсорсное решение, а есть какой-то платный продукт, похожий или другой, за счёт которого монетизируется разработка. В итоге, когда у нас Selenoid полетел, мы просто приняли решение и оформили это в виде компании. Теперь это уже коммерческая организация, которая имеет опенсорс и имеет свои продукты.
— То есть ты в ней работаешь, получается?
Ваня: Да.
— Хорошо. Аня, ты писала библиотеку Akita, которая разрабатывалась в Альфа-Банке. Ты до сих пор используешь её где-то активно? Или она так и осталась в Альфе и всё?
Аня: Она разрабатывалась как раз в рамках Альфа-Банка. В первую очередь она была для их нужд. Потом мы её заопенсорсили, потому что показалось, что она может быть ещё кому-то полезна. Насколько я знаю, в банке её сейчас используют, конечно, и ещё, может, около десятка сторонних организаций. Но я сейчас с ней не работаю.
— Ты продвигала BDD. Ты где-то его сейчас продвигаешь или это уже не та тема, которой ты активно занимаешься?
Аня: Это тоже зависит от ситуации. Если приходит заказчик и говорит, что я хочу быть в курсе того, что происходит, тогда да, им этот подход хорошо ложится. Если этим занимаются фича-команды, либо тестирование вынесено отдельно как сервис, то тогда в этих случаях я это не продвигаю. С BDD я какое-то время уже не работала, сейчас в основном это self-healing автоматизация.
Использование BDD в 2020 году. Это шутка?
— BDD в 2020 году это окей?
Аня: Я думаю, что окей, но зависит от ситуации. Сейчас у нас в этом же Альфа-Банке self-healing с BDD тестируют и всё нормально. Типа его можно апдейтить, именно этот BDD-подход делать более стабильным и тогда это хорошо работает.
Ваня: По сути BDD — это же для менеджеров было изначально. Чтобы человек, не имеющий очень глубоких компетенций в разработке тестов мог тем не менее довольно легко прочитать, как тестируется продукт, разобраться. Мне кажется, до тех пор, пока организационно вся разработка строится так, что есть руководители-менеджеры, которые имеют разные компетенции и есть разработчики, я думаю, что BDD имеет смысл, почему нет?
Аня: Ещё есть ситуации, например, как в банке были, что в командах просто не было тестировщика, и нужно было это как-то тестировать, и аналитики сказали: «вот мы хотим!». Для них как раз этот инструмент в том числе и разрабатывался. Приходили практически к этой идеальной формулировке BDD, что аналитики тоже задействованы в написании сценариев, и им было удобно руководствоваться этим верхнеуровневым описанием шагов, чтобы составлять тесты, и они могли автоматически запускаться.
— Этот холивар до сих пор идёт, кто же всё-таки должен писать тесты на BDD? Например, есть какая-то организация, у которой нет ещё BDD, и непонятно нужен он или не нужен, и кто должен эти тесты писать. В идеальном мире что бы вы посоветовали?
Ваня: Мне кажется, это сильно зависит от количества всего.
Аня: Да, и от ситуации сильно зависит. Если это feature team, где есть все представители этих ролей и какой-нибудь тестировщик с хорошими хард скиллами, и таких команд много, и именно так организация строится, то им BDD вряд ли нужен будет. Если это команда, где нет тестировщика, либо у тестировщика слабые хард скиллы, например, это в основном ручное тестирование, то тогда этот подход тоже будет применим, потому что тестировщик сможет ещё и автоматизацией заниматься сразу же.
— То есть если у вас очень много денег и вы наняли очень много людей, которые некомпетентны технически, то BDD вам подходит?
Аня: В принципе можно так сказать.
Ваня: Мне вообще кажется, что не только BDD, а любое тестирование при планировании должно сильно отталкиваться от денег.
У нас так сложилось, что большинство конференций всё-таки в техническую или в философскую сторону двигаются. Не принято что ли говорить о том, что в любом случае всё равно мы работаем в компаниях, у которых есть бюджеты, у которых есть какое-то ограниченное количество денег. Все решения, которые принимает руководство, оно всё равно в конце концов упирается в эти самые деньги. Тут никуда не денешься. Просто программисты, тестировщики и аналитики, мы варимся в таком «ограниченном» мире, где нам про них не говорят, могут сказать только «делаем» или «не делаем». Мне кажется, что и тестирование, и планирование разработки, и всё остальное — нужно всегда отталкиваться от имеющегося бюджета, не более того. Всё равно всё упирается туда.
BDD в аутсорсе или у себя?
— Если говорить о том, BDD для аутсорсного проекта и для внутреннего — есть какая-то разница или нет? Если бюджет позволяет, нужен BDD на аутсорс?
Аня: Здесь опять-таки да, всё в бюджет упирается. Не знаю, на аутсорс я, наверное, лично BDD бы не отдавала, но если, конечно, заказчик прям сильно не хочет. Если говорит: «хочу BDD и всё, мне вот всё равно!» — вот тогда да. Но на это нужны будут такие скилованные ребята, чтобы они красиво это всё обернули в какой-нибудь красивый фреймворк. Обычно на аутсорс приходят клиенты, которые говорят: «Я быстро хочу какую-нибудь автоматизацию», — или — «У меня нет автоматизации, постройте», — или — «У меня всё плохо, давайте что-то как-то обновим». Обычно в таких ситуациях их решение требует более глубокого технического понимания и автоматизации на техническом уровне.
Хотя если ложится клиенту хорошо и можно быстро стартануть автоматизацию, тоже, наверное, от времени зависит. Если можно таким способом быстро стартануть и достичь цели, которую хочет клиент, то тогда да, может лечь.
— Кажется, что BDD для аутсорса это не только про то, как написать им проект, выяснив требования, а ещё про то, чтобы научить клиентов вообще понимать, что там. Потому что обучение каких-нибудь аналитиков или даже менеджеров пониманию того, как они должны сценарии составлять, если будут в дальнейшем — это тоже отдельная история.
Аня: Да, в этом могут быть свои сложности.
Ваня: Возвращаясь к вопросу о том, является ли BDD нормальным в 2020 году, мне кажется, есть какая-то определённая эволюция, это я так в философскую сторону ухожу…
У нас со временем появляются всякие новые подходы и технологии, и мне кажется, не бывает такого, чтобы технология полностью умерла. Например, 40 лет назад, когда развивались именно компьютеры, были мейнфреймы эти огромные машины, которые сейчас практически умерли, тем не менее остались определённые ниши, где они до сих пор существуют и отлично работают.
Фотография с сайта www.kmd.dk
Я буквально недавно общался с человеком, он как-то с банками связан, с какими-то старыми американскими, он говорит: «У нас стоит всё сорокалетней давности, всё работает, потому что дешевле это всё поддерживать, чем переписать на новое». Точно так же, я думаю, и в тестировании, появляются новые подходы, появилось BDD. Я не думаю, что оно вообще умрёт, оно останется в каких-то нишах, даже если придумают что-то лучше этого. Так с любым продуктом, с любой технологией. Нельзя, с одной стороны, полностью, на сто процентов захватить весь рынок, с другой стороны, и умереть тоже полностью — нужно постараться, чтобы это произошло, всегда остаются какие-то ниши. Вопрос в том, какая их доля в общей массе людей.
Карьерный рост
— Все решения очень бизнес-ориентированы всегда, и как ты сказал, обычные инженеры не особо думают о деньгах, о бизнесе и о рисках бизнеса и не понимают, может быть, зачастую, почему такие решения.
Ваня: Часто задают вопрос: как вырасти в компании? Приходят младшие разработчики, джуниоры и, естественно, у них в голове цель — как бы вырасти. В конечном счёте в какой-то момент начинаешь чувствовать бизнес-требование, что там деньги нужно считать и так далее. По сути дела, способ вырасти в какого-то более высокого уровня начальника-разработчика — это начать даже на такой невысокой должности думать о том, а как бы ты с точки зрения бизнеса это начал делать. Не с точки зрения, какой бы я сейчас клёвый новый язык попробую или ещё что-то, это круто для личной экспертизы собственной, но с точки зрения бизнеса, если хочется вырасти, мне кажется, нужно вот про это больше думать.
Способ вырасти в какого-то более высокого уровня начальника-разработчика — это начать даже на такой невысокой должности думать о том, а как бы ты с точки зрения бизнеса это начал делать.
В своё время слышал умного человека. Он рассказывал, что существуют разные способы вырасти карьерно. Он перечислил три основных способа. Первый способ — это быть чьим-то родственником. Такого обычно мало, маленькое количество людей, у кого есть какие-то там родственники высокие руководители. Второй способ — это заниматься манипуляциями. Всякие интриги плести в компании и так далее. Таких людей, которые умеют это делать, тоже мало. И третий способ — это доказывать работой свою полезность компании. Основная идея роста заключается в том, чтобы в компании найти такую нишу, в которой есть проблемы. И предложить своему руководству, как эти проблемы эффективно решить, вот в таком случае можно сильно вырасти.
— Ваня, ты сказал, что для того чтобы развиваться разработчик должен думать о бизнесе дальше. Должны ли разработчики общаться с пользователями своих продуктов? У меня, например, есть в команде ребята, которые говорят: «Ой, знаете, я пришёл писать код, для того чтобы с миром вообще не общаться! Пишите мне ТЗ хоть километровое, я буду сидеть, писать код».
Ваня: Тут всё очень сильно зависит от человека и от команды. По большому счёту, если человек хочет развиваться и расти, ему всё равно в какой-то момент придётся это делать. До какого-то момента времени за него будет общаться менеджер, если он у него есть, но если он в итоге хочет развиваться, ему придётся это делать. Чем ведущий разработчик отличается от старшего? Тем, что у него есть очень хорошая экспертиза и тем, что он умеет решать такие уже полуменеджерские задачи. Он умеет нести полную ответственность за тот продукт, который он делает от составления требований до непосредственно разработки, вот в этом отличие, мне кажется.
Аня: Да, здесь идёт понимание того, для чего ты что-либо делаешь, а не просто так сделать — клёво будет.
Selenium. Нужен ли он еще?
— Давайте поговорим про Selenium, раз уж тут собрались специалисты этой тематики. Есть вопрос от телезрителя: «Почему кто-то до сих пор выбирает писать тесты на Selenium? Насколько вообще это оправданный выбор, учитывая что можно писать на разных уровнях тесты и, может быть, вообще никогда не добраться до тестов на Selenium?»
Аня: Сейчас часто говорят, что Selenium умирает. Какие-то другие инструменты приходят на его место. Мне кажется, что это не совсем так и всё равно всё зависит от экспертизы. В любом случае большинство проектов сейчас на Selenium делается и делалось на нём. Нужна будет поддержка, и если как специалист по тестированию хочешь куда-нибудь устроиться, то, скорее всего, это будет Selenium. Экспертизы в этой области, наверное, гораздо больше, плюс когда выходят какие-то новые технологии на рынок, она может бомбануть и потом скатиться куда-нибудь. Selenium покрывает, я бы сказала, все возможности юайного тестирования. И это такая как бы мощная штука, которая в ближайшее время точно не умрёт.
Если как специалист по тестированию хочешь куда-нибудь устроиться, то, скорее всего, это будет Selenium.
Ваня: Я ещё хочу дополнить. С технологиями всегда есть определённая инерция. Selenium, как известно, существует с 2004 года, ему уже 15 лет. Он, конечно, тоже меняется сам по себе, тем не менее за это время накопилось довольно большое количество уже готовых проектов. Для программирования 15 лет назад — это каменный век по сравнению с тем, что есть сейчас. И накоплено больше опыта именно в Selenium. Просто начать даже съезжать на какую-то новую технологию, если ты уже опытный автоматизатор, это сложно, это реально инерция.
Поскольку продукт существует долго, по нему накоплена большая база знаний, подводные камни, даже если — это проблема не только Selenium, это вообще проблема любой новой технологии, — чтобы она полетела, нужно набрать какую-то критическую массу из знаний, пользователей и так далее.
У Selenium есть критическая масса пользователей, есть форумы, сообщества, Stack Overflow, куча документации, куча конференций и специалистов, которые могут эти знания передавать постоянно. Как только возникает новая технология, она может полететь сейчас только в том случае, если в неё будет вбухана куча денег — и всё упирается в деньги.
Есть пример не про тестирование, а про разработку. Есть язык программирования Kotlin. Он сейчас, как выяснилось, полетел в мобильном направлении, прям летит-летит. Говорят, ходят какие-то слухи о том, что просто в его продвижение вложено довольно приличное количество денег, чтобы он в конференциях везде упомянался, чтобы люди разрабатывали фреймворки. Так много с чем происходит. Чтобы преодолеть инерцию, нужно затратить какое-то количество ресурсов. Просто сделав хороший продукт, даже если он реально лучше Selenium, сложно его продвинуть.
Почему Selenium? Потому что это теперь стандарт. Есть конкретный World Wide Web Консорциум, который взял и зафиксировал стандарт Selenium. Всегда лучше работать с инструментами, которые стандартизованы. Выбирая между двумя инструментами, можно сказать: «Здесь у нас всё зафиксировано, API стабильное, всё хорошо, а вот есть какое-то непонятное поделие сбоку, которое тоже делает какая-то компания, непонятно сколько она просуществует». При выборе между этими двумя инструментами, как правило, разумный менеджер обычно делает выбор в пользу чего-то более стандартного. Мне кажется, что писать тесты на Selenium имеет смысл, потому что даже какому-то начинающему специалисту сейчас проще это сделать. Порог входа будет ниже — больше тех, у кого можно спросить про Selenium.
Вторая причина, почему нужно продолжать писать тесты на Selenium, почему вообще нужно писать тесты на UI. Фактически написание тестов на UI, таких вот end-to-end — это единственный способ проверить, что приложение работает ровно так же, как это увидит пользователь. Даже если мы пишем всякие юниты и всё остальное, покрываем разными типами тестирования, это не даёт стопроцентной гарантии. Только проиграв те же самые действия, которые будет делать пользователь приложения, мы можем быть на сто процентов уверены, что у нас приложение работает. Понятно, что не нужно все сто процентов кода таким образом проходить. Обычно покрываются самые критически важные сценарии в приложении, но тем не менее это важно.
Всегда лучше работать с инструментами, которые стандартизованы.
Аня: По поводу новых инструментов хотела ещё добавить. Когда-то слышала умного дядьку на конференции. Он рассказывал про старт новых технологий и как понять, какая технология умрёт, какая задержится. У любой технологии, которая на рынок выходит, она начинает набирать то, что Ваня как раз говорит, критическую массу. Потом у неё происходит бум, и вот этот бум нужно как бы переждать, потому что после этого бума либо эта технология остаётся, его выдерживает, дальше у неё будет своё развитие и скачок, либо она после этого умрёт. Это тоже зависит от инвестиций, от того, успевает ли команда разработки справиться с тем потоком пользователей, которые на них приходят, потоком багов, либо направлений для дальнейшего развития, либо нет. Вот так сразу хвататься за что-нибудь, что находится на хайпе и переводить свои тесты на эту технологию, это, мне кажется, будет неоправданно.
— Как вам кажется, много ли изменилось в Selenium? Изменилось ли вообще что-то за последние два года драматически в этом инструменте и эволюционирует ли он как-то?
Ваня: Мне кажется, он довольно сильно меняется. Года два или три назад было ощущение, что в нём какой-то застой был, потому что по сути дела Selenium придумали в 2004 году, потом он развивался-развивался-развивался, потом в 2008-2009 году придумали Selenium WebDriver, придумали Selenium Grid. После этого лет пять они просто допиливали его, выкатывали какие-то небольшие фичи, в общем сильно ничего не менялось. У всех стоял Selenium Grid, у всех была стандартная библиотека Selenium.
А вот последние года 2-3 пошёл бум всяких новых продуктов, основанных на Selenium. Мы, например, сделали Selenoid. Ребята, которые работали в тот момент в компании Zalando, на основе Selenium Grid сделали такой инструмент как Zalenium, тоже Selenium-совместимое решение. По сути оба инструмента были сделаны для того, чтобы решить какие-то конкретные проблемы, для которых не было решения в оригинальном коде. Потом появились ещё другие, конкуренты самого Selenium. Сейчас, мне кажется, последние года два или три пошла какая-то такая движуха-движуха.
Мне кажется, что Selenium развивается, плюс ещё в начале 2018 года зафиксировали стандарт. Поэтому Selenium, конечно, с одной стороны, как инструмент довольно сильно заматерел. С другой стороны команде, которая развивала первоначально основной код, удалось навязать ответственность за поддержание совместимости со стандартом другим командам разработчиков браузеров. Если раньше фактически весь Selenium был какой-то единый, в котором всё лежало, все драйверы, то теперь им удалось договориться со всеми командами. Apple для Safari делает поддержку, потому что есть стандарт и не нужно ни с кем согласовывать. Google делает для Chrome поддержку, Mozilla делает для Firefox. Фактически теперь это уже распределённая экосистема, там есть несколько разных точек. Сейчас Microsoft тоже делает для своих браузеров своё, для Edge он делал свой драйвер, и им удалось ответственность распределить. За счёт этого, мне кажется, произошёл довольно приличный скачок в качестве.
— Да, три года назад, я помню, чтобы тесты на Selenium на Safari бежали, нужно было себя так выкрутить. В общем больно было.
Ваня: А теперь всё по стандарту сделано более-менее. Там, конечно, есть какие-то свои особенности, но по сути всё стало единообразно, то есть произошла такая унификация того, как это всё работает внутри. Мне кажется, это круто, там много усилий было вложено в это всё. Поэтому я не считаю, что сейчас в Selenium есть какой-то застой. Сейчас там есть здоровая конкуренция разных решений.
Мы в каком-то смысле конкурируем с ребятами, которые делают основной код Selenium. Приезжаем на конференции, говорим, что ребята, ваше не эффективное потому, потому и потому. Чтобы как-то доказать, что всё-таки они тоже молодцы, им приходится делать своё. Происходит здоровая конкуренция.
Аня: По поводу Selenium IDE ещё хочется добавить, про которую вообще, мне кажется, все давно забыли. С появлением новых инструментов по script-less автоматизации они опять взялись за Selenium IDE. В течение 2019 года очень сильно её развивали и планируется масштабный релиз в начале 2020 года, где они что-то представят. Очень сильно поменялся интерфейс у IDE и она стала более стабильной и удобной, скажем так.
Ваня: Хотел ещё добавить, что сейчас к Selenium стали пытаться прикладывать разные технологии, которые до этого не применялись, например, то же самое машинное обучение.
Это одно из направлений, которое до сих пор не существовало в Selenium. Люди, попользовавшись Selenium лет 10, обнаружили какое-то количество задач, которые, как выяснилось, могут быть частично или полностью решены при помощи машинного обучения. Всякие рутинные операции.
— Аня, расскажи, что за проблемы вы решаете машинным обучением? Всё за нас будут писать? У нас сейчас искусственный интеллект начинает проникать вообще везде. Если вбить в Google «AI и Selenium» — там начинают люди разрабатывать свои какие-то библиотеки, выкладывать, ещё что-то, то есть развитие идёт.
Аня: Относительно Selenium могу сказать, что в последнее время гораздо удобнее на основе него делать всякие решения, ну в частности это за счёт его стандартизации. По поводу возможностей, самое главное нужно — это взаимодействовать с элементами на странице. И соответственно эта часть уже ложится, на тестировщиков, как это взаимодействие описать, используя Selenium. Если это описывать чисто используя Selenium, то могут быть нестабильные тесты, потому что какие-то там изменения произойдут на UI, какого-то элемента не дождутся и так далее. Машинное обучение начинают именно к этому месту прикладывать, чтобы можно было эти тесты стабилизировать. Чтобы эти тесты можно было сгенерить на основе информации, которая имеется у нас на странице, и на основе поведения пользователя.
В тренде было Record and Play, то, что делает как раз Selenium IDE: мы заходим на страницу, накликиваем действие, у нас создаются тесты. Эти тесты должны быть стабильные. Машинное обучение нужно там именно для этого. Обычно локаторы захардкожены, поэтому при изменениях на UI их необходимо обновить. Healenium, который мы сейчас делаем, например, позволяет в рантайме их обновить, и наш тест, соответственно, пройдёт.
Сейчас появляется такая тенденция не чисто к Record and Play тестам, а к возможности генерации тестов. Мы знаем, какие у нас есть элементы на странице. Мы можем нарисовать некую логическую схему нашего сайта. Мы знаем, что у нас есть главная страничка, от неё страничка логина и ещё чего-то. Основываясь на этих логических связях и действиях, которые мы можем делать на этой странице, мы можем сгенерировать тесты. Но таких инструментов на рынке, которые прям очень хорошо это сделали, я пока не знаю. Healenium мы хотим развивать как раз в этом направлении.
С развитием этих подходов и знаний в области machine learning в ближайшее время будет уклон в развитие и появление таких инструментов. Например, краулеров сайтов, которые могут автоматически провести тестирование вместо написания тест-кейсов.
— Вот Ваня сказал, что Selenium IDE обновляют. В общем, не то они делают. Скоро машинное обучение всё за них решит и это IDE даже не нужно будет.
А если машинное обучение будет действительно таким крутым, то какая часть останется живым людям, тестировщикам?
Предлагаю обсудить этот вопрос в комментариях. А в продолжении этого интервью мы узнаем ответы Анны и Ивана. Кстати, на конференции Heisenbug 2020 Piter, которая пройдет в онлайне, можно будет пообщаться с ними и подробнее узнать про Healenium, Selenoid и использование Chrome DevTools протокола в Kubernetes кластере.
Недавно вышла вторая часть интервью с ответом на вопрос про ML в тестировании: узнали, кто такой человек-маркировщик, и разобрались, нужно ли изучать Selenium в 2020 году.
Для тех, кто хочет расширить кругозор и посетить не одну конференцию, а сразу 8 — мы кое-что подготовили.
Как выполнять много UI-тестов параллельно, используя Selenium Grid? / Блог компании Авито / Хабр
Всем привет! Я работаю в Avito и занимаюсь разработкой инструментов для тестирования. Когда у нас стало много UI-тестов, мы столкнулись с проблемой масштабирования Selenium-серверов, и сейчас я расскажу, как мы ее решили.
И так как же все-таки выполнять много UI-тестов параллельно, используя Selenium Grid? К сожалению — никак.
Selenium Grid не способен выполнять большое количество задач параллельно.
Хотите зарегистрировать действительно большое количество нод? Что ж, попробуйте.
Хотите скорости? Её не будет — чем больше нод зарегистрировано на гриде, тем менее стабильно выполняется каждый тест. Как следствие — перезапуски.
Хотите отказоустойчивость на случай, если Grid перестал отвечать? Тоже нет: вы не можете запустить несколько реплик и поставить перед ними балансировщик.
Хотите обновить Grid без даунтайма и чтобы тесты, выполняющиеся в данный момент, не упали? Нет, это не про Selenium Grid.
Хотите не держать тысячи Selenium-ов разных конфигураций в памяти, а поднимать их по требованию? Не получится.
Хотите знать, как решить все эти проблемы? Тогда приглашаю вас прочитать эту статью.
*(Мой доклад с таким же названием уже звучал на Heisenbug 2017 Moscow, и, возможно, кто-то из читателей с ним знаком. Под катом — более подробная текстовая версия рассказа об инструменте).
Небольшое отступление, о том как работает Selenium-сервер.
- Для того, чтобы начать управлять браузером нужно послать запрос
create session
на Selenium-сервер. - В результате на ноде открывается браузер, а к вам возвращается токен
sessionId
, отправляя который в каждом запросе, вы управляете браузером.
Окей, а зачем нужен Selenium Grid? Selenium Grid предоставляет единую точку для работы со множеством Selenium-серверов разной конфигурации:
- он позволяет создавать сессию на свободной ноде, подходящей под ваши критерии фильтрации, например, по версии браузера;
- хранит информацию о том, какая сессия открыта на какой ноде и проксирует все запросы на целевую ноду, таким образом для клиента нет разницы работать с одной нодой, или с гридом.
Замечательный инструмент, правда?
Но при его использовании мы столкнулись с рядом проблем.
1. Непредсказуемое поведение
Если кратко, то у вас отвалится что захочет и когда захочет, и вы никак не сможете на это повлиять.
- Мы очень часто сталкивались с ситуациями, когда тесты отлично работали в один поток, но при многопоточном выполнении через грид были непредсказуемые падения.
- Периодически на часть нод тесты просто не попадали, хотя физически они были доступны, на гриде скапливалась очередь из тестов. В итоге половина релизного сьюта отваливалась по таймауту.
2. Отсутствие поддержки большого количества нод
При попытке зарегистрировать много нод (а мы хотим много нод), регистрация произойдет, но протестировать приложение во много потоков все равно не получится, так как большая часть тестов упадет.
3. Масштабируемость
Первое, что приходит в голову, когда достигнут предел нод = N на селениум гриде, при котором не страдает стабильность, — это взять два, три, пять, (да хоть десять) гридов, зарегистрировать на каждый по N нод, вкрячить перед всем этим добром какой-нибудь балансировщик и запускать тесты в 10*N потоков. Но нет, Selenium Grid так не работает. Потому что вся информация о нодах и сессиях хранится в памяти у конкретной ноды и не шарится между ними. С этим тесно связана следующая проблема.
4. Отказоустойчивость
Если у вас выключается машина, где находится хаб, то все тесты сразу умирают, потому что у вас нет никаких резервных хабов, на которые могут идти следующие запросы, ибо опять же, все лежит в памяти. И это абсолютно никак не смасштабировать (конечно же, всегда можно переписать пару классов грида, но об этом позже). Слабое место — это Selenium Hub, при его падении ноды становятся недосягаемыми.
5. Отсутствие возможности динамического создания нод с использованием система оркестрации контейнерами
Если для тестирования вам необходимо множество различных конфигураций нод с разными конфигурациями браузеров, то возникает еще одна проблема: весь этот зоопарк занимает довольно много места в памяти. Предположим, у вас: 300 нод с Google Chrome (150GB RAM) + 300 нод с Firefox (150GB RAM) и еще 200 нод какого нибудь Firefox Nightly c магическими плагинами (100GB RAM). 400GB RAM постоянно заняты, плюс хочется эффективно перераспределять ноды в течение дня, скажем, занять все 400GB семью сотнями хромов при тестировании одного сьюта и гибко заменять их при появлении в очереди тестов с другими потребностями.
Для решения этой задачи идеально подойдет Docker, так как он позволяет быстро поднимать контейнер со свежим Selenium и так же быстро его убивать после завершения теста. И так как селениумов нам нужно много, на один железный сервер все это не влезет, возникает потребность в оркестрации контейнеров на кластере. На рынке существует несколько популярных решений для этой задачи, у нас используется Kubernetes. Почему мы выбрали Kubernetes, можно послушать здесь. Стандартными средствами Selenium эту проблему не решить.
6. Невозможно обновить/перезапустить грид без даунтайма
Еще одно следствие хранения сессий в памяти. Не то чтобы это суперкритичный минус, но всё равно неприятный.
Все вышеперечисленное — это ситуация, в которой мы в один прекрасный момент оказались.
Grid Router и новая реализация Go Grid Router — хорошее решение, но к сожалению далеко не идеальное. Основная проблема особенность, то что это не замена для Selenium Hub, это еще одна прокси сверху.
Отсюда и название — Grid Router, потому что он управляет не нодами, а гридами, поэтому есть минусы.
- Попытка создания новой сессии происходит не на гриде со свободными нодами, а на случайном (можно управлять распределением случайной величины при помощи весов). Если на одном из гридов не удалось создать сессию, запрос пойдет на следующий, и так пока не закончатся гриды. Таким образом время создания новой сессии может затягиваться на значительные промежутки времени.
- Если один из селениум хабов упадет, то вся информация о сессиях будет потеряна, а ноды отключены от сети. Так как до сих пор все взаимодействия идут через хаб и данные о сессиях хранятся в хабе.
- Довольно трудно добавить еще один хаб в систему, потому что данные о хабах хранятся в xml-файликах и синхронизация с файлами происходит по сигналу операционной системы. Транзакций нет, все плохо.
Selenoid — средство для запуска тестов в docker-контейнерах. При каждом запросе на создание сессии запускается свежий контейнер и при закрытии сессии удаляется. Инструмент замечательный, но есть минусы:
- не поддерживает ни одну систему оркестрации;
- все еще хранит информацию о сессиях в памяти, и, как следствие, имеет проблемы с масштабированием и отказоустойчивостью.
Когда мы столкнулись со всеми этими проблемами, мы решили поинтересоваться опытом других компаний. «Яндекс» писал в блоге на Habrahabr о том, что не получается регистрировать много нод и работать с ними, для решения этой проблемы они используют Grid Router. Для наших задач Grid Router не подходит.
«Альфа-Банк» писал о том, что у них все повисает, если grid какое-то время не использовать, и наш опыт это подтверждает — у нас то же самое было регулярно.
Конечно же мы не обделили вниманием github selenium, где нашли несколько issue… Вот пример отношения авторов к происходящему:
Q: «selenium-grid version 3.0+ support hub high availability?»
A: «I would recommend having a separate server monitor the hub and then if/when the hub goes down it would know how to restore the hub.»
Мы поняли, что надеяться нам не на что, и стали сами решать свои проблемы.
Мы решили начать с простого пути, задеплоили в kubernetes кластер некоторое количество селениумов, сложили ip в БД и непосредственно в setUp()
теста ходили в базу брали оттуда ip, который дольше всех не использовался и запускали тест, нигде не храня sessionId
и не блокируя ноды. Так как воркеров с тестами было < количества селениумов, переполнения не должно было происходить.
Это решение сразу показало свою жизнеспособность.
Мы получили:
- предсказуемое поведение;
- отказоустойчивость на уровне БД;
- масштабируемость;
- поддержку большого количества нод;
- upgrade без остановки тестов, потому что это просто код, который лежит у вас в репозитории, и запускается, когда запускаются тесты.
Но столкнулись с рядом проблем:
- нет поддержки механизма выбора Capabilities;
- нет удобного механизма /grid/register;
- отсутстует Portability — система больше не работает как сервис, зависит от одного языка программирования и реализована в одном репозитории с тестами.
Последняя проблема — самая важная, потому что если вы зашиваете это в код тестового фреймворка, то вам автоматически нужно поддерживать это в каждом вашем тестовом фреймворке, во всех репозиториях на всех используемых языках.
Самое главное в этом эксперименте — полученный опыт. Мы убедились в том, что Selenium Grid можно реализовать нормально.
Первым делом мы стали рассматривать идею с форком/пулл реквестом селениума. Но после более детального знакомства с кодом проекта мы поняли, что дешевле и надежнее писать свой велосипед.
Давайте еще раз перечислим, что мы хотим от нового инструмента:
- предсказуемость поведения;
- отказоустойчивость;
- масштабируемость;
- portability;
- поддержка большого количества нод;
- поддержка Capabilities;
- on-demand Node in Kubernetes;
- сбор метрик в statsd;
- механизм /grid/register;
- upgrade без остановки тестов.
Что в итоге получилось:
- приложение, которое решает все вышеперечисленные задачи;
- кроссплатформенное приложение, тестировали на linux и macos;
- написано на Go;
- хранит данные в mysql.
В итоге нам удалось решить все задачи. Приложение написали на Go. Само приложение stateless — сессии хранятся в mysql, при желании не сложно поддержать любую другую БД. On-demand создание контейнеров реализовано только в Kubernrtes, но вы можете прислать пулл реквест с реализацией методов создания/удаления контейнера в любой другой системе. Go компилируется под разные платформы, но нам достаточно было протестировать работоспособность только на linux и macos, в теории других системах проблем быть не должно.
Теперь главный вопрос. Сколько нам строчек кода тестов пришлось переписать в процессе перехода на этот инструмент? Кто считает, что 10000/1000/100? Ноль! Ничего не надо было переписать, он полностью совместим. Просто нужно задеплоить приложение и указать его адрес, и все. Больше ничего делать не надо.
В итоге получилась такая схема:
Как этим пользоваться? Есть 2 режима:
- Persistent — здесь всё как раньше, запускаете селениум сервер c параметром
-role node
, указываете где адрес хаба, нода регистрируется, можно пользоваться:
java -jar selenium-server.jar -role node -hub http://127.0.0.1:4444/grid/register
- On-demand — в конфиг грида нужно добавить докер-образы и информацию о том, какие capabilities они реализуют. Дальше запускаете грид, запрашиваете сессию, нода сама создается в кластере.
...
"type": "kubernetes",
"limit": 20,
"node_list": [
{
"params": {
"image":"myimage:latest",
"port": "5555"
},
"capabilities_list": [
{
"browserName": "firefox",
"browserVersion": 50
...
Мы уже довольно долгое время используем это решение в продакшене, оно работает и не требует никакой поддержки. В процессе мы еще раз убедились в том, что не стоит бояться делать велосипеды. Популярные решения — это не всегда хорошо, нужно всегда исследовать возможности для решения проблем.
Что должен знать каждый QA-инженер о Selenium 4?
Привет, друзья. Май богат новыми курсами, и прямо сейчас, в преддверии запуска курса «Java QA Engineer», мы продолжаем публиковать полезный материал для QA-специалистов.
Вернемся в август 2018 года, когда сообщество тестировщиков потрясла новость о том, что Саймон Стюарт, один из основателей Selenium, официально утвердил дату релиза и афишировал некоторые основные обновления Selenium 4 на Selenium Conference в Бангалоре. Четвертая версия всеми любимого фреймворка для автоматизации веб-тестирования должна была быть выпущена к рождеству 2018 года.
Дата релиза Selenium 4
Те, кто уже знаком с историей релиза Selenium 3, который тоже должен был случиться к рождеству, предполагали, что новая версия будет закончена к рождеству, но скорее всего не 2018 года. Ровно также, как это произошло с предыдущей версией, которая была выпущена на три года позже официально объявленной даты.
И они были правы! На сегодняшний день (даже с обновленной информацией о выпуске Selenium 4 в феврале 2019 года), официального релиза все еще не было.
Также не поступало какой-то официальной информации о новых датах выпуска со стороны основателей проекта. Однако как мы видим на официальной странице проекта SeleniumHQ на Github, разработчики закрыли только половину задач, которые было необходимо сделать, поэтому справедливо можно предположить, что официального релиза не случится до рождества 2019 года.
В чем важность Selenium 4?
Если вы считаете, что инженеры по автоматизации тестирования – единственные люди в мире, которые должны заботиться о выходе обновления Selenium, вы ошибаетесь. Конечно же, Selenium стал отраслевым стандартом для проведения автоматизированного тестирования. Он считается первоочередным инструментом для тестирования веб-приложений уже слишком масштабных для проведения ручного тестирования.
Остается без внимания и то, что компании, которые в значительной степени полагаются на Selenium – не просто компании, кто имеют в своем штате QA-инженеров, но еще и те, кто пользуется интегрированными инструментами автоматизированного бескодового тестирования на базе того же Selenium. Тестирование без кода на базе Selenium стало настоящим спасением для компаний, которые осознают необходимость в автоматизации, но не имеют в своем штате QA-экспертов, которые могли бы с этим разобраться. Такие инструменты не только делают возможным развертывание для тех, кто имеет базовое представление о веб-браузерах, но и позволяют запускать регрессионные тесты, выполнять синтетический мониторинг и нагрузочное тестирование без каких-либо знаний фреймворка Selenium.
Основные изменения в Selenium 4
Теперь давайте перейдем к списку вещей, которые SeleniumHQ обещали добавить или изменить в следующей версии.
Стандартизация WebDriver W3C
Во-первых, Selenium 4 WebDriver будет полностью стандартизирован W3C. API WebDriver стало актуальным и за пределами Selenium и теперь используется в различных инструментах для автоматизации. Например, на нем основываются такие мобильные инструменты для тестирования, как Appium и iOS Driver. Стандарт W3C также отвечает за совместимость между различными программными приложениями с WebDriver API.
Вот как Selenium Grid взаимодействует с исполняемыми файлами драйверов на данный момент:
Тест в Selenium 3.x взаимодействует с браузером в конечном узле (end node) по протоколу JSON wire в локальной конечной точке (local end). Такой подход требует кодирования и декодирования запросов API.
Судя по обновлениям, которые мы ожидаем увидеть в Selenium 4, тест будет взаимодействовать напрямую без кодирования и декодирования запросов API через протокол W3C. Несмотря на это, в привязке к Java все еще будет обратная совместимость, но в центре внимания будет протокол консорциума W3C. А вот протокол JSON wire использоваться больше не будет.
Над спецификациями W3C WebDriver работают несколько разработчиков, и весь процесс вы можете увидеть на GitHub.
Selenium 4 IDE TNG
Selenium IDE поддерживает Chrome «из коробки». Как известно, Selenium IDE – это инструмент записи и воспроизведения. Теперь он будет доступен со следующим, более богатым и продвинутым функционалом:
- Новая система плагинов. Теперь любой поставщик браузера сможет легко «подключиться» к новой среде Selenium IDE. Вы сможете использовать свою собственную стратегию идентификации элементов (locator strategy) и плагин Selenium IDE.
- Новый CLI runner. Он будет полностью основан на NodeJS, а не на HTML, как было раньше, также он будет иметь следующий возможности:
- WebDriver Playback. Новый Selenium IDE runner будет полностью основан на WebDriver.
- Параллельное выполнение. Новый CLI runner будет поддерживать параллельное выполнение тестов и предоставит полезную информацию, такую как затраченное время, а также набор пройденных и неудачных тестов.
Улучшенный Selenium Grid
Каждый, кто когда-либо работал с Selenium Grid знает как сложно его настраивать. Selenium Grid поддерживает выполнение тестов в разных браузерах, операционных системах и машинах, обеспечивающих параллельное выполнение.
В Selenium Grid есть два основных элемента: Hub и Node.
Хаб (hub) работает как сервер, центральный пункт управления всеми тестируемыми машинами в сети. В Selenium Grid всего один хаб, который выделяет определенный узел на выполнение теста в соответствии с его потенциалом.
Узел (node), простыми словами, — тестируемая машина, на которой запущены тесты.
Чтобы узнать больше, советуем вам прочитать полное официальное руководство по Selenium Grid.
До настоящего времени процесс присоединения узла к хабу в Selenium Grid вызывал у тестировщиков серьезные сложности.
В Selenium 4 работа с Grid обещает быть простой, так как больше не будет необходимости настраивать и запускать хабы и узлы отдельно. После запуска сервера Selenium, Grid будет работать одновременно как узел и как хаб.
Selenium 4 будет поставляться с более стабильной версией Selenium Grid. Будут устранены ошибки потокобезопасности и улучшена поддержка Docker.
Улучшенный пользовательский интерфейс Selenium Grid
Еще одним приоритетом в разработке Selenium 4, который был выделен во время официального анонсирования, оказалось создание более удобного пользовательского интерфейса Selenium Grid, который будет отражать всю соответствующую информацию о сессиях, мощности и т.д.
Улучшенная наблюдаемость (observability)
“Пассивная наблюдаемость – это способность делать описательную трассировку»
— Саймон Стюарт
Наблюдаемость, логи и отладка больше не ограничиваются DevOps. В рамках грядущего релиза, трассировка запросов и запись логов с хуками (hooks) будут улучшены, чтобы обеспечить для инженеров по автоматизации возможность отладки.
Обновленная документация
Документация играет ключевую роль в успехе любого проекта. Документация Selenium не обновлялась с выпуска Selenium 2.0. Это значит, что каждый, кто пытался изучить Selenium в последние несколько лет, пользовался старыми туториалами.
Таким образом, естественно, обновленная и современная документация, которую SeleniumHQ обещает предоставить нам вместе с версией 4.0, стала одним из самых ожидаемых обновлений Selenium в сообществе автоматизации тестирования.
Тем не менее, вы все еще можете получить доступ ко всей существующей документации Selenium.
Selenium 4 в двух словах
Здесь перечислены все основные изменения, которые мы, вероятно, увидим, когда наконец состоится релиз Selenium 4. Если вам интересно узнать больше об истории фреймворка, ее основателях и новых функциях Selenium, мы предлагаем посмотреть это видео с конференции Selenium 2018 года, где был анонсирован релиз.
Пишите комментарии и записывайтесь на день открытых дверей, который пройдет уже 22 мая. До встречи в ОТУС!
Что такое селен? Введение в Selenium Automation Testing
- Home
Testing
- Back
- Agile Testing
- BugZilla
- Cucumber
- Database Testing
- 94000
- 000
- 9000 J27 Тестирование
- 9000 J27 JUnit
- LoadRunner
- Ручное тестирование
- Мобильное тестирование
- Mantis
- Почтальон
- QTP
- Назад
- Центр качества (ALM)
- RPA
- SAP Testing
Управление тестированием Soap
- TestLink
SAP
- Назад
- ABAP 900 04
- APO
- Начинающий
- Basis
- BODS
- BI
- BPC
- CO
- Назад
- CRM
- Crystal Reports
- FICO
- 000
- 000 HRM
- 000
- 000 HRM
- 9000 Заработная плата
- Назад
- PI / PO
- PP
- SD
- SAPUI5
- Безопасность
- Менеджер решений
- Successfactors
- Учебники SAP
- Apache
- Назад
- Java
- JSP
- Kotlin
- Linux
- Linux
- Kotlin
- Linux
- Perl
js
- Назад
- PHP
- PL / SQL
- PostgreSQL
- Python
- ReactJS
- Ruby & Rails
- Scala
- SQL
- SQL
- UML
- VB.Net
- VBScript
- Веб-службы
- WPF
000
000
0003 SQL
000
0003 SQL
000
Обязательно учите!
- Назад
- Бухгалтерский учет
- Алгоритмы
- Android
- Блокчейн
- Business Analyst
- Создание веб-сайта
- CCNA
- Облачные вычисления
- 00030003 COBOL
- 9000 Compiler
- 00030002 9000 Compiler
- Ethical Hacking
- Учебники по Excel
- Программирование на Go
- IoT
- ITIL
- Jenkins
- MIS
- Сети
- Операционная система
- 0003
- Назад
- Управление проектами Обзоры
- Salesforce
- SEO
- Разработка программного обеспечения
- VB A
- 9000 Встроенные системы
- 00030002 9000 Compiler
Big Data
- Назад
- AWS
- BigData
- Cassandra
- Cognos
- Хранилище данных
- HBOps
- HBOps
- MicroStrategy
0003
0003
.
Тестирование производительности :: Документация по Selenium
Selenium
- Начало работы
- Краткий обзор
- Краткий обзор
- Введение
- Проект и инструменты Selenium
- Об автоматизации тестирования
- Виды испытаний
- Об этой документации
- Проект и инструменты Selenium
- Установка селена
- Установка библиотек Selenium
- Установка двоичных файлов WebDriver
- Установка автономного сервера
- Установка библиотек Selenium
- Начало работы с WebDriver
- Браузеры
- Сторонние драйверы и плагины
- Установочные элементы
- Выполнение действий на АВ *
- Браузеры
- WebDriver
- Понимание компонентов
- Требования к драйверам
- Манипуляции с браузером
- Ожидание
- Классы поддержки
- Предупреждения, подсказки и подтверждения JavaScript
- Http прокси
- Стратегия загрузки страницы
- Веб-элемент
- Клавиатура
- Понимание компонентов
- Удаленный WebDriver
- Удаленный сервер WebDriver
- Клиент удаленного WebDriver
- Удаленный сервер WebDriver
- Указания
- Страничные объектные модели
- Доменный язык
- Создание состояния приложения
- Макет внешних услуг
- Улучшенная отчетность
- Избегать совместного использования состояния
- Независимость испытаний
- Рассмотрите возможность использования свободного API
- Свежий браузер за тест
- Страничные объектные модели
- Наихудшие практики
- Captchas
- Двухфакторная аутентификация
- Загрузки файлов
- Коды ответа HTTP
- Gmail, электронная почта и Facebook
- Тестовая зависимость
- Тестирование производительности
- Звездочка звена
- Captchas
.
Аннотации, структура, примеры в Selenium
- Home
Testing
- Back
- Agile Testing
- BugZilla
- Cucumber
- Database Testing
- Назад
- JUnit
- LoadRunner
- Ручное тестирование
- Мобильное тестирование
- Mantis
- Почтальон
- QTP
- Назад
- Центр качества (ALM)
- SAP Testing
- SAPU
- Управление тестированием
- TestLink
SAP
- Назад
- ABAP
- APO
- Начинающий
- Basis
- BODS
- BI
- BPC
- CO
- Назад
- CRM
- Crystal Reports
- QM4000
- Заработная плата
- Назад
- PI / PO
- PP
- SD
- SAPUI5
- Безопасность
- Менеджер решений
- Successfactors
- Учебники SAP
- Apache
- AngularJS
- ASP.Net
- C
- C #
- C ++
- CodeIgniter
- СУБД
- JavaScript
- Назад
- Java
- JSP
- Kotlin
- Linux
- Linux
- Kotlin
- Linux
js
- Perl
- Назад
- PHP
- PL / SQL
- PostgreSQL
- Python
- ReactJS
- Ruby & Rails
- Scala
- SQL
- SQL
000
000
0003 SQL
000
0003 SQL
000
Обязательно учите!
- Назад
- Бухгалтерский учет
- Алгоритмы
- Android
- Блокчейн
- Business Analyst
- Создание веб-сайта
- CCNA
- Облачные вычисления
- 00030003 COBOL
- 9000 Compiler
- 00030002 9000 Compiler
- Ethical Hacking
- Учебники по Excel
- Программирование на Go
- IoT
- ITIL
- Jenkins
- MIS
- Сети
- Операционная система
- 0003
- Назад
- Управление проектами Обзоры
- Salesforce
- SEO
- Разработка программного обеспечения
- VB A
- 9000 Встроенные системы
- 00030002 9000 Compiler
Big Data
- Назад
- AWS
- BigData
- Cassandra
- Cognos
- Хранилище данных
- HBOps
- HBOps
- MicroStrategy
- MongoDB
0003
0003
.
Top 100 Selenium Interview Вопросы и ответы
- Home
Testing
- Back
- Agile Testing
- BugZilla
- Cucumber
- Database Testing
- Назад
- JUnit
- LoadRunner
- Ручное тестирование
- Мобильное тестирование
- Mantis
- Почтальон
- QTP
- Назад
- Центр качества (ALM)
- SAP Testing
- Управление тестированием
- TestLink
SAP
- Назад
- AB AP
- APO
- Начинающий
- Basis
- BODS
- BI
- BPC
- CO
- Назад
- CRM
- Crystal Reports
- QM4O
- Заработная плата
- Назад
- PI / PO
- PP
- SD
- SAPUI5
- Безопасность
- Менеджер решений
- Successfactors
- SAP Tutorials
4
- Web
- Apache
- AngularJS
- ASP.Net
- C
- C #
- C ++
- CodeIgniter
- СУБД
- JavaScript
- Назад
- Java
- JSP
- Kotlin
- Linux
- Linux
- Kotlin
- Linux
js
- Perl
- Назад
- PHP
- PL / SQL
- PostgreSQL
- Python
- ReactJS
- Ruby & Rails
- Scala
- SQL
- SQL
000
000
0003 SQL
000
0003 SQL
000
Обязательно учите!
- Назад
- Бухгалтерский учет
- Алгоритмы
- Android
- Блокчейн
- Business Analyst
- Создание веб-сайта
- CCNA
- Облачные вычисления
- 00030003 COBOL
- 9000 Compiler
- 00030002 9000 Compiler
- Ethical Hacking
- Учебники по Excel
- Программирование на Go
- IoT
- ITIL
- Jenkins
- MIS
- Сети
- Операционная система
- 0003
- Назад
- Управление проектами Обзоры
- Salesforce
- SEO
- Разработка программного обеспечения
- VB A
- 9000 Встроенные системы
- 00030002 9000 Compiler
Big Data
- Назад
- AWS
- BigData
- Cassandra
- Cognos
- Хранилище данных
- HBOps
- HBOps
- MicroStrategy
- MongoDB
0003
0003
.