Автоматизированные веб тесты на C++ - так, конечно, мало кто делает. Наиболее подходящий для этой задачи язык - это, конечно, Java. Однако, бывают такие случаи когда все же необходимо реализовать подобный функционал на плюсах. Скорее всего, подобные задачи никак не относятся к тестированию и скорее всего это задачи парсинга сайтов и майнинг информации. Но даже в этом случае, лучше всего подойдет Java.

Возможность реализовать эту задачу на C++ есть, с помощью JsonWireProtocol, который предоставляет нам selenium-server.

Все реализации WebDriver, которые взаимодействуют с браузером или удаленным сервером WebDriver, используют common wire protocol. Этот протокол определяет RESTful веб сервисы, с использованием JSON поверх HTTP. Протокол допускает что WebDriver API может быть размазано (то есть отличаться в разных версиях WebDriver), но ожидает, что реализация на стороне WebDriver имеет хороший ООП подход, как демонстрируется в Java API. Wire протокол реализует пару запрос-ответ для взаимодействия с WebDriver.

В общем-то все понятно. Необходимо реализовать запрос-ответ JSON объектов, поверх HTTP. Это все просто реализуется с помощью того же CURL. Однако, набор команда для работы с браузерами не такой маленький и поэтому это немного накладно будет по времени реализовывать это все с нуля.

Поэтому давайте воспользуемся готовой библиотекой, которую я поддерживаю - Webdriver++. Решая подобную задачу я на гитхабе нашел один репозиторий, последний коммит в котором был 3 года назад, но большинство функций в этом проекте уже было реализовано. Я немного доработал этот проект, исправил пару багов и сделал его как Shared Library. Теперь есть возможность использовать Webdriver++ в любом вашем C++ проекте.

Как использовать

  1. Скачать selenium-server с сайта Selenium.
  2. Клонировать проект Webdriver++ себе на компьютер
  3. Собрать проект
         mkdir build
         cd build && cmake ..
         make && sudo make install
    
  4. Запустить selenium-server
         java -jar selenium-server-standalone-3.5.0.jar
    
  5. Создать свой проект на C++ и можете использовать этот пример:

Советы по оптимизации быстродействия

  1. Не запускайте каждый раз новую сессию WebDriver, при обращении к новым URL, если в этом нет особой необходимости. Запускайте только одну сессию WebDriver в одном потоке и используйте ее для всех задач. Таким образом сократиться очень много времени на инициализацию сессии WebDriver.
  2. Отлаввливайте исключения webdriverexception, и если таоке случилось, то освободите все ресурсы, удалите сессии WebDriver, запустите новую.
  3. Используйте HtmlUnit. Я провел эксперименты, использовал Firefox WebDriver, Chrome WebDriver, PhantomJS, HtmlUnit. Наиболее быстрым и менее глючным для моих задач оказался HtmlUnit. Конечно, Chrome WebDriver так же показал хорошие результаты по стабильной работе, но все же Chrome потребляет больше ресурсов и мне так и не удалось запустить его без GUI (пытался использовать параметры –headless, не помогло).

Альтернативные решения

Я использую WebDriver для майнинга данных, в коммерческом проекте и поэтому вопрос производительности и работы с памятью стоит очень критично. Грубо говоря, чем быстрее я обработаю/смайню данные, тем больше будет профит. Поэтому вариант c selenium мне не особо нравится, потому что этот процесс занимает ресурсы, особенно оперативную память. В идеале было бы работать с браузером на прямую, но пока такого варианта нет.

Поэтому я собираюсь провести еще ряд экспериментов по этому вопросы и возможно сделаю новый open source проект по работе с WebDriver на C++, однако, от работы через Java никуда не деться.

Какие есть вараинты

  • Реализовать полностью все на Java. Такой вариант подойдет, если у вас, кроме использования WebDriver никаких других функий в софте не предусмотрено.
  • Вызывать напрямую методы из Java библиотеки, с помощью JNI. Ну то есть генерировать, с помощью javah header файл и далее вызывать методы Java, напрямую из C++. Кажется это более чем разумный вариант.
  • Реализовать небольшую Java программу и передавать в нее команды из C++, по сути аналог selenium-server, но уже более оптимизированный и без лишних наворотов. Общение между приложениям возможно реализовать как через сокеты, так и воспользоваться менее болезненным способом и взять ZeroMQ для решения задачи коммуникаций между приложениями.
  • Инвертировать проблему, то есть вызывать C++ методы из Java. Если у вас есть функционал, который работает только на C++, вы можете создать библиотеку и с помощью механизма JNI вызывать необходимые методы библиотеки.

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

Поэтому я пожалуй реализую свой велосипед и сделаю второй вариант C++ <-> JNI <-> Java , чтобы выжать из этого максимум. Тогда это будет быстрее, с точки зрения написания кода. Осталось провести эксперименты.

Удачи мне.