Есть отличная удаленная работа для php+codeception+jenkins+allure+docker спецов. 100% remote! Присоединиться к проекту

[Web driver] Запуск набора тестов в разных браузерах


(s.kaliberda) #1

Всем привет!

Может быть кто-то сталкивался с пробемой запуска тест сьюта в разных браузерах с помощью Selenium WebDriver.

Нужно настроить несколько конфигураций на TeamCity с одинаковым набором тестов, но вот каждая конфигурация будет запускать тест сьют на специфическом браузере.

Например:

1. Smoke tests suite on Firefox

2. Smoke tests suite on Opera

3. Smoke tests suite on IE

......

Можно ли каким-то параметром через командную строку передать переменную браузера, как параметр TestNG или  с помощью Maven?

С радостью выслушаю другие варианты решения этой задачи.

 


(Дмитрий Жарий) #2

 

Я с таким не сталкивался. 
Но, могу подсказать, наверное, самый старый способ передачи данных между программами. 
Это переменные окружения. 
Поддержка чтения или записи переменной есть в любом языке. 
 
В TeamCity вы можете установить переменную перед запуском TestNG:
Set BROWSER=FireFox
 
И прочитать ее из Java
http://docs.oracle.com/javase/tutorial/essential/environment/env.html
 
 Отпишитесь пожалуйста, если этот совет помог либо если вы нашли более элегантное решение
 

(s.kaliberda) #3

 

На другом форуме подсказали как можно решить эту задачу с помощью Maven.

Запускаем тесты с командной строки

mvn clean integration-test -Dwebbrowser=opera


Кусок pom, в котором задаем значение по умолчанию, а в тестирующую систему передаем через jvmargs:code

<properties>
   ....
<selenium.test.webbrowser>firefox</selenium.test.webbrowser>
   ....
<selenium.test.jvmargs><![CDATA[-Dwebbrowser=${selenium.test.webbrowser}]]></selenium.test.jvmargs>
   ....
</properties>
   ....
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.version}</version>
<configuration>
    <argLine> -Xmx128m -Xms128m -XX:MaxPermSize=196m ${selenium.test.jvmargs}</argLine>
</configuration>




В коде переменную можно вытащить таки образом

String browser = java.lang.System.getProperties().getProperty("webbrowser");
 

 


(s.kaliberda) #4

 

На другом форуме подсказали как можно решить эту задачу с помощью Maven.

Запускаем тесты с командной строки

mvn clean integration-test -Dwebbrowser=opera


Кусок pom, в котором задаем значение по умолчанию, а в тестирующую систему передаем через jvmargs:code

<properties>
   ....
<selenium.test.webbrowser>firefox</selenium.test.webbrowser>
   ....
<selenium.test.jvmargs><![CDATA[-Dwebbrowser=${selenium.test.webbrowser}]]></selenium.test.jvmargs>
   ....
</properties>
   ....
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.version}</version>
<configuration>
    <argLine> -Xmx128m -Xms128m -XX:MaxPermSize=196m ${selenium.test.jvmargs}</argLine>
</configuration>




В коде переменную можно вытащить таки образом

String browser = java.lang.System.getProperties().getProperty("webbrowser");
 

 


(Дмитрий Жарий) #5

 

Спасибо


(Hohner) #6

Приветствую!

Я тут набросал свое видение реализации. Буду благодарен за конструктивную критику.

 

public class TestClass
{
    public static void main(String[] args)
    {       
        WebDriver[] drivers = new WebDriver[2];
        drivers[0] = new FirefoxDriver();
        drivers[1] = new InternetExplorerDriver();
        
        for (WebDriver e : drivers)
        {
            e.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
            e.get("http://mail.ru");
            e.findElement(By.id("mailbox__login")).sendKeys("Robin Hood");
            e.close();
        }
    }
}
 


(Mykhailo Poliarush) #7

подход нормальный в контексте запуска одного или двух тестов

но если так делать для 100 или 1000 тестов, но запуск и интеграция c CI будет проблематичной

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

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


(apetrovskiy) #8

100 тестов или 100 браузеров? Запуск процесса - весьма дорогое удовольствие, а каждый чесиный тест требует на себя два процесса, брайзер и драйвер (кроме, пожалуй, лиса?).

Обещается, что ког-да-нибудь к нам прибудет добавка серверов - я постараюсь узнать, сколько селениумов в параллель можно запустить. :)

 

По поводу параллельного запуска - вот пример на пяти инстансах одного браузера (чтобы проще было понять сделующий за этим примером код):

if (5 -eq (Start-SeChrome -Count 5 | Enter-SeURL "http://google.com" | Get-SeWebElement -Name q | Set-SeWebElementKeys cheese | Submit-SeWebElement).Count) {Write-Host "OK"} else {Write-Error "test failed"}; sleep -Seconds 10; Stop-Process -Name chrome;

это реализация затасканного примера с сайта селениума про поиск сыра.

Start-Se[Browser] запускает пять инстансов, депозитит процесс айди и настоящий хэндл окна (а не фуфло сами знаете откуда получаемое :)), после запуска последнего браузера - этот браузер становится текущим и любой код нового пайплайна будет работать для него.

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

Если надо распараллелить и шаги, тогда надо инстансы браузеров депозитить в переменные

 

$drivers = Start-SeChrome -Count 2; $drivers | Enter-SeURL "http://google.com"; $drivers | Get-SeWebElement -Name q; и т.д.
это очень грубый пример кода, с кучей аутпута в консоль (лень облагораживать)
 
Наконец, вернёмся к теме запуска в нескольких браузерах:
if (5 -eq ($(Start-SeChrome -Count 2; Start-SeFirefox -Count 3) | Enter-SeURL "http://google.com" | Get-SeWebElement -Name q | Set-SeWebElementKeys cheese | Submit-SeWebElement).Count) { Write-Host "OK"; } else { Write-Error "test failed"; }; sleep -Seconds 10; Stop-Process -Name chrome,firefox
 
Тут Миша заметил, что в одном из тестов может выскочить терминирующая ошибка. Да, в этих командлетах тоже (потому что если не запустился браузер, не снавигировал или не нашёл контрол - часто дальше нет смысла терять время).
В случае шарпа и джавы, это, вероятно, делается через try-catch (или более хитро), у нас это делается довольно просто: 
$ErrorActionPreference = [System.Management.Automation.ActionPreference]::SilentlyContinue;
конечно, тоже зависит от командлет, но обычно означает, что до поры до времени ошибки подавляются, а решение принимается где-то на последних стадиях специально написанным для этого кодом.
 
ЗЫ: Слип - это оператору теста уважуха, посмотреть, что получилось, подвигать мышкой инстансы (селениум же не переводит инстанс в foreground, как это делает UI Automation - кстати, спасибо мне за идею микро-фичи :)). Код 

(Mykhailo Poliarush) #9

100 браузеров это конечно затратно, но если есть такая потребность то почему бы и нет

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

я уже не раз сталкавался с примерами проектов, где тысячи тестов на разных браузерах запускаются и проходят в течении 10-20 минут

так что, вопрос тут только в целесообразности и понимании, нужно это или нет


(Hohner) #10

Спасибо.

Допустим с Exception при прогоне я поборюсь с помощью Try, Catch Finally (хотя не до конца уверен :) ).

А в чем проблема при использовании в CI (допустим Jenkins)?


(apetrovskiy) #11

Сам давно подумываю перебраться в клауд со своими проектами (пока нет идеи по поводу недорого аплоада, да и менеджемент тулов нет для амазона. МС поставляет командлеты, но облако дороже). Да ещё хотелось бы и собирать на 8/2012, а их ещё в клауде нет.

 

Интересно, а что эти проекты там запускают? Селениум на линуксах или как-то умудряются (через Selenium RC или ещё как) запускать на windows?

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


(Mykhailo Poliarush) #12

что запускают? тесты

самые известный, например, провайдер сейчас https://saucelabs.com/

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

правда это все денег стоит, но я сам пользовался удобно 

минимальное время прогона - это время самого долгого теста в твоем наборе

в общем, если есть деньги и возможность, рекомендую

 

а как сделано, да просто у них кластера и селениум grid, ничего сверх естественного


(Mykhailo Poliarush) #13

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

но обычно при большом количесве тестов, тесты параметризируются, маркируются организовываются в сьюты, и запускаются через юнитфреймворки

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

я согласен, что программно можно сделать любую логику запуска тестов, но потом придется делать снова изобретать велосипед типа с возможностями junit или testng

в общем, я бы так не делал


(Hohner) #14

Ясно. Спасибо за ответы.

Не буду спорить, так как не имею большого опыта и соответственно большого количества тестов. Ну, а то что придется делать велосипеды с кастомным репортером, это очевидно (в отличии от готовых дефолтных репортов в TestNG, например).


(Hohner) #15

И еще вопрос: выше приведен пример с использованием Maven. Я с ним не знаком. Суть примерно ясна, но не могу сообразить как реализовать подобное с помощью Ant.


(Mykhailo Poliarush) #16

а я спорить тоже не хочу,

я просто хочу помощь и уберечь от неприятных последствий :)


(apetrovskiy) #17

А, понятно, не "люди", а конторы-провайдеры и конторы-клиенты (нижележащий слой, конечно, люди). Я, конечно, подумал в разрезе самопальных запусков (это ещё живёт привычка с давних времён - чтобы собрать компьютер, надо поехать на рынок, купить мелкосхем (желательно оптом, а продать в розницу - чтобы "свои" вышли дёшево или бесплатно), долго-долго смотреть на материнскую плату, чтобы найти все дефекты, проверить мелкосхемы на самопальном сигнатурном анализаторе, потом всё это собрать, отладить (ненайденные дефекты материнки и привнесённые дефекты пайки), ну и постепенно ввести в строй. А потом продать, потому что надо отдавать деньги, взятые на покупку мелкосхем. :) вот так, вспомнилось, пока Торвальдс уже оси писал, мы тут ещё паяли только).

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

 

Для аутсорса эти тестовые облачные конторы рулят, тут можно сразу включить в счёт их счёт, и ещё рисков 50/100 или сколько надо процентов. :) Посмотрю, что они предлагают, интересно.

А самопальные запуски и фреймворки идут как раз от двух причин: поставщик включает в счёт много лишнего (включая запрлату менеджеров и оплату уборки офиса в день тестирования, не считая порше), а сервис порой не превосходит сделанное для себя "как для себя". Нус, посмотрим на них.


(Mykhailo Poliarush) #18

я думаю можно вынести эту тему отдельным топиком :)


(Mykhailo Poliarush) #19

ну надо сначала написать что вы уже пробовали и что у вас не получается.

в ant есть jvmarg и arg

попробуйте вот так и можете также читать этот агрмент через системыные свойства

 

<junit fork="yes" ...>
    <jvmarg value="-Dbrowser=firefox" />
</junit>

(Hohner) #20

Ест еще такой вариант запуска в разных браузерах.

 

В TestNG есть такая вещь как Parameters. Пример из документации:

@Parameters({ "first-name" })

@Test
public void testSingleString(String firstName) {
  System.out.println("Invoked testString " + firstName);
  assert "Cedric".equals(firstName);

}

 

Тогда в наш tesng.xml добавим параметр "browser" и наши тесты (допустим тест логина) будут выглядеть примерно как

@Parameters({"browser"})
    @Test
    public void loginTest(String browser)

{ ваш код теста}

 

метод для инициализации драйвера будет выглядеть следующим образом:

protected static WebDriver getWebDriver(String browser)
    {
        if (driver == null)
        {            
                File pathToBinary = new File("pathTo\\firefox.exe");
                FirefoxBinary ffBinary = new FirefoxBinary(pathToBinary);
                FirefoxProfile firefoxProfile = new FirefoxProfile();
                driver = new FirefoxDriver(ffBinary,firefoxProfile);    
        }
        
        if (browser.equalsIgnoreCase("chrome"))
        {
            System.setProperty("webdriver.chrome.driver", "pathTo\\chromedriver.exe");
            driver = new ChromeDriver();
        }
        
        driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
        return driver;
    }

 

Теперь создаем два xml файла, допустим Suite1.xml и Suite2.xml. Эти файлы идентичны и отличаются только значением параметра "browser".

 

Теперь отредактируем наш testng.xml:

<suite name="CrossBrowserSuite" verbose="1" >
  <test name="MainWorkflow" >
  </test>
  <suite-files>
   <suite-file path="./suite1.xml" />
   <suite-file path="./suite2.xml" />
  </suite-files>
</suite>

 

Теперь будет иметь место следующая последовательность: выполняется suite1 в одном браузере -> браузер закрывается -> запускается второй браузер -> выполняется suite2 -> второй браузер закрывается.

 

Немного громоздко, но, по-моему, имеет право на жизнь ))

 

Минусы очевидны: suite1.xml и suite2.xml просто копии друг друга. с другой стороны, а вдруг есть необходимость запускать разные наборы в разных браузерах (хотя сам я в это не верю).