Thucydides. Смена драйвера во время выполнения тестов из одной Story

thucydides
bdd
internet-explorer
firefox
chrome
activex
Теги: #<Tag:0x00007fedb9665b30> #<Tag:0x00007fedb9665950> #<Tag:0x00007fedb96653b0> #<Tag:0x00007fedb9665270> #<Tag:0x00007fedb9665130> #<Tag:0x00007fedb9664ff0>

(inkvizitorz) #1

Есть определенный набор тестов, принадлежащей одной Story. Тесты взаимосвязаны и выполняются строго в одном порядке (это жестко связано с тестируемым функционалом).

Необходимо часть тестов из Story выполнить только из под Internet Explorer'а (часть тестируемого функционала, к сожалению, использует ActiveX).

Остальные тесты можно выполнять из любого браузера (FireFox, Chrome, IE) - задается в командной строке для maven с помощью параметра -Dwebdriver.driver
В коде это выглядит примерно так:

public class MyStoryTest () {
    ...
    public void test1() {}
    
    public void test2() {}
    
    public void test3() {}
    
    public void test4() {}
    ...
}

Вопрос - как сделать так, чтобы во время последовательного выполнения тестов 1-4 в рамках MyStoryTest test3, например всегда выполнялся бы из под IE?

Остальные тесты при этом могут выполняться из любого браузера (FireFox, Chrome, IE).


(Дмитрий Мирошник) #2

Не совсем понял вопрос, попробую угадать.
Что подразумевается под взаимосвязанными тестами? Тест 2 использует результат теста 1? Или тест 2 стартует из точки окончания теста 1? Попробую привести примеры:

1.)
Тест 1. Создаём через форму продукт и сохраняем его.
Тест 2. Заходим через просмотрщик продуктов, находим созданный в тесте 1 продукт, проверяем, что всё отображается нормально.

Или

2.)
Тест 1. Логинимся в приложение.
Тест 2. Используя эту же сессию, заходим куда-нибудь.

Для случая 1 всё просто: инициализировать драйвер в тесте. Таким образом, для каждого теста поднимается отдельный драйвер и браузер, что есть правильно с точки зрения проблем с кешем, утечками памяти и прочей браузерной радости.

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

  1. Тестим всё под IE. Если часть функционала работает под IE - значит, весь функционал также должен под ним работать, если иное не указано в требованиях.
  2. Если есть необходимость проверить работу остальной части тестов под другими браузерами разбиваем тесты на 2 группы: IE и Other, к примеру, затем, аналогично случаю 1, инициализируем драйвер для части тестов 1 раз для тестов 1 - 4, 1 раз для тестов 5 - N. Проблема, которая может возникнуть: стыковка тестов 4 и 5. Возможно, придётся повторить часть шагов, чтобы привести тест 5 к правильному начальному состоянию.
  3. Разбиваем стори на 2 части. 1 тестируем под IE, 2-ю - под чем хотим. Инициализируем драйвер по дефолту через maven для каждой из частей стори.

(inkvizitorz) #3

Defender, спасибо за ответ и желание помочь)
Под взаимосвязанными тестами подразумевается следующее:

Тест 1:

  • логинимся под user1 на портал или в административную консоль;
  • делаем какие либо действия, проверяем что-либо, создаем какие-нибудь объекты из предметной области, ищем что-то;
  • запоминаем для передачи в следующий тест какие-либо значения, например, СНИЛС или id объекта или url;
  • разлогиниваемся на портале/ в консоли.

Тест 2 (IE only):

  • логинимся под user2 на портал или в административную консоль;
  • делаем какие либо действия, проверяем что-либо, создаем какие-нибудь объекты из предметной области, ищем что-то;
  • запоминаем для передачи в следующий тест какие-либо значения, например, СНИЛС или id объекта или url;
  • разлогиниваемся на портале/ в консоли.

Тест 3:

  • логинимся под user1 на портал или в административную консоль;
  • делаем какие либо действия, проверяем что-либо, создаем какие-нибудь объекты из предметной области, ищем что-то;
  • запоминаем для передачи в следующий тест какие-либо значения, например, СНИЛС или id объекта или url;
  • разлогиниваемся на портале/ в консоли.

То есть, в каждом тесте сначала логинимся, в конце разлогиниваемся.
Порядок тестов практически везде строгий. Т.е. исходя из сценария тестирования, например нельзя выполнить сначала тесты 3, 5, 8 (которые IE only),
а затем выполнить тесты 1,2,4,6,7,9,10

По поводу вашей рекомендации тестировать все в IE.
Самая большая Story, написанная мной, состоит из 17 тестов (каждый тест примерно из 5-15 шагов) из них 3 теста работают только из под IE.

Если любой тест падает, Story считается непройденным, а функционал неработающим.
Вероятность успешного прохождения всех тестов из Story (практически вычисленная) меньше 1/10.
Помогает использование в строке запуска мавена параметра "число попыток перезапуска упавшего теста", например так -Dmax.retries=5.

В итоге 17 тестов выполняются под IE за 25-30 минут. Время ручного тестирования функционала Story превышает 2 часа.

Замеры времени выполнения нескольких тестов до теста, который IE only, показали, что под FireFox и Chrome время их выполнения примерно в 2 раза меньше, чем под IE.

Также я заметил и посчитал (убил сутки) практическую вероятность прохождения части тестов с одной попытки для IE (примерно 0,1), FireFox (0,4) и Chrome (0,4).
Для уменьшения времени выполнения тестов данной Story я решил выполнять все в FireFox или Chrome, а для тестов под IE принудительно стартовать еще один драйвер.
В итоге получилось некрасиво, коряво, есть мелкие проблемы, мне самому не нравится, но работает.

Время выполения в итоге уменьшилось до 10-11 минут.
Пример кода (прошу строго не судить, на Java я пишу с нуля со 2-го января 2015, автоматизированным тестированием занимаюсь полгода, Thucydides осваиваю тоже с января).

    public class ServiceStoryTest {
        ...
         @BeforeClass
        public static void beforeClass() {
            driverType = Injectors.getInjector().getInstance(Configuration.class).getDriverType().toString();
        }
    
        @Before
         public void setUp() throws Exception {
            if (!(driverType.equalsIgnoreCase("IEXPLORER"))&&(checkMethod)) {
                driver = new InternetExplorerDriver();
            }
           }
    
        @After
          public void tearDown() throws Exception {
            if (!(driverType.equalsIgnoreCase("IEXPLORER"))&&(checkMethod)&&(terminateDriver)) {
                terminateDriver=false;
                checkMethod=false;
                driver.quit();
            }
        }
        ...
        @Test  //9  
        public void e_sign_file() throws Exception {  
            if (driverType.equalsIgnoreCase("IEXPLORER")) {
                user.should_be_visible_service_entrance_page();
                user.should_be_visible_console_ppu_page(login2, password2);
                user.should_be_signed_file(urlApprovalRoutePage);
            } 
            else {
                driver.get("HOST/access.htm");
                driver.findElement(By.xpath(".//input[@name='login']")).clear();
                driver.findElement(By.xpath(".//input[@name='login']")).sendKeys(login2);
                driver.findElement(By.xpath(".//input[@name='password']")).clear();
                driver.findElement(By.xpath(".//input[@name='password']")).sendKeys(password2);
                driver.findElement(By.xpath(".//form//input[@title='Вход']")).click();
                ....
            }
        ....
    }

Минусы данного решения:

  • в случае падения теста под IE остаются всякие незакрытые ресурсы - окна браузера и т.п., которые не дают нормально выполнятся тесту при повторе;
  • приходится фактически дублировать весь код теста на чистом WebDriver'е (код в секции else);
  • в таком виде не годится для будущего CI (конец этого года примерно, кода наберется много тестов).

Исходя из всего вышеизложенного я и обратился к уважаемым форумчанам за помощью.
Хотелось бы узнать о других вариантах реализации.


(vmaximv) #4

Я бы посоветовал просто "довести" эти циферки до единички, чем "выбирать меньшее зло" статистическим путем - добром оно от этого не станет.


(inkvizitorz) #5

1 никак в консоли не получается, там много окон, фреймов и AJAX.
С кодом теста не связано. Может, например, не увидеть элемент на открытой странице и т.п.
Все места, где что-либо более/менее стабильно (т.е. хотя бы через пару раз на третий) падало, я переписал - подобрал другие локаторы, поменял логику и т.п.

Тем не менее все замечательно работает с опцией в строке запуска мавена параметра "число попыток перезапуска упавшего теста", например так -Dmax.retries=5.

И сутки были потрачены не зря. Я получил статистику по скорости и стабильности выполнения тестов в разных браузерах применительно к самому тяжелому сценарию тестирования.
В других сценариях вероятность гораздо выше, от 0,7.


(vmaximv) #6

Не ройте себе яму - эта цифра "пять", со временем может стать и "десяткой" и "двадцаткой".
Тесты должны быть стабильными - если рандомно падают, это надо исправлять, а не ранать n-раз, в надежде "авось_пройдет". И если этого не делать, то чем больше будет таких тестов, тем печальнее результат.


(Дмитрий Мирошник) #7

Так-с.

Во-первых, стабилизируйте тесты. Покурите, как работать с Ajax и используйте скриптовые определители завершения загрузки страницы вместо таймаутов, которые, я подозреваю, Вы используете. Запомните, для Ajax WaitForPageToLoad не работает.

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

В-третьих, используйте waits для поиска элементов. Я бы рекомендовал написать wrapper над findElement с конфигурируемым таймаутом. Для всяких выпадающих списков и прочей динамически генерируемой лабуды здорово повышает стабильность тестов.

В-четвёртых, если есть много окон и фреймов, я бы рекомендовал проверить Ваши локаторы через findAll. Не исключено, что на странице находятся несколько элементов, попадающих под критерии поиска и Вы рандомно захватываете 1 из них при рестарте теста.


(inkvizitorz) #8

1) Таймауты сейчас не использую. Для описания локатора использую аннотацию @FindBy.
Перед непосредственной работой с элементом вызываю метод waitUntilEnabled().
Метод WaitForPageToLoad не использую. Кроме того, опытным путем установлено, что FireFox и Opera в моем случае намного стабильнее IE8 (минимально поддерживаемая версия) - а код один и тот же.

2) Для разработки и тестирования использую виртуальную машину, т.к. есть куча ограничений для основной ОС - доменная безопасность для браузера и т.п. На виртуалке я сам себе админ.
Соответственно вопрос - как программно из теста прибить процессы браузера? Или я вас не так понял?

3) Можно здесь поподробнее?

4) На основной странице консоли есть 3 фрейма. Я написал метод переключения, использующий переключение в основной контекст, а затем в нужный фрейм. Работает стабильно.
Локаторы я пишу и тестирую в плагине к FireFox'су FirePath. Для IE использую замечательную утилиту от Дмитрия Жария Swd_Page_Recorder. Все локаторы пишу руками, автосгенерированные не использую. Обычно локаторы не сложнее такого .//*[@id='work']//form//input[@name='email']
Не было еще проблем с двумя одинаковыми локаторами, поэтому findAll не применяю.
На странице с фреймами проблемы иногда возникают и при ручном тестировании (при клике на элемент в одном фрейме сервер не отдал содержимое в другой. Или после клика ничего не происходит). Возникающие иногда проблемы с переключением между окнами решены с помощью запоминания handle текущего окна.

P.S. большое спасибо за ответ. Но мне очень важно сейчас все-таки найти альтернативное решение по смене драйвера во время выполнения. Разбиение на несколько стори не подходит, так как их кол-во сразу увеличится в несколько раз и, кроме того, между ними придется передавать параметры и запускать в строго определенной последовательности.


(vmaximv) #9

Я просто решу задачку по терверу за второй курс матфака.
P=(1-p)^n, где n - кол-во испытаний, p - вероятность события, P - вероятность, что событие p не произойдет ни в одном из испытаний.
P=(1-0.4)^5=0,07776 = 7,776%

Пусть есть три сценария с вероятностью фейла 7,776%
Вероятность, что при их запуске хотя бы один из них упадет будет:
P=1-(1-0.07776)^3~0,22=22%

По этим формулам можете самостоятельно прикинуть "динамику", например 100 сценариев с "вероятностью успешности" 0,9


(Дмитрий Мирошник) #10

2). http://stackoverflow.com/questions/6356340/killing-a-process-using-java
Для винды вот так:
Runtime.getRuntime().exec("taskkill /F /IM .exe")
3). Используйте explicit waits: http://docs.seleniumhq.org/docs/04_webdriver_advanced.jsp. Я для удобства писАл статический класс, в котором складировал методы типа таких вот врапперов. Потом в тесте это выглядело как-то так:
...
MyClass.findElementWithExplicitWait (driver, myLocator, timeout).

4). Хм... Ну, если приложение само по себе нестабильно - то в 1-ю голову надо его фиксить. Пытаться стабилизировать тесты на нестабильном приложении - задача неблагодарная.

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


(inkvizitorz) #11

Я с вами совершенно согласен, надо повышать стабильность тестов.
Но нужно учитывать следующие факты.

  1. у нас есть портальная часть ПО и консольная (обе работают только в браузере). Но портальная с точки зрения автоматизации проще, т.к. там практически нет фреймов и редко появляются дополнительные окна браузера (алерты не в счет).
  2. соответственно, априори, можно ожидать, что тесты для портальной части будут стабильнее при всех прочих равных условиях.
  3. апостериори, это подтверждается. У меня есть один средней продолжительности тест для портальной части, где есть загрузка файлов, алерты и AJAX. У меня после 4-5 прогонов тест ни разу не падал. Я отдал его коллеге - за месяц использования падений не было (т.е. еще минимум десяток прогонов был).
  4. для выбора ПО для автоматизации тестирования я лично проверил именно в консольной части в той или иной степени порядка 7-8 штук разного ПО, начиная от AutoIt и заканчивая HP Unified
    Functional Testing 12. Так вот, для пары небольших тестов на AutoIt'e я явно реализовывал ожидания элементов (работал с ними через DOM). Так вот, иногда явно наблюдались ситуации, когда сервер тупо что-либо не отдавал. Т.е. был виден клик по папке в одном фрейме, а во втором ничего не обновлялось. Или явно была нажата кнопка и ожидалось открытие нового окна, но оно не происходило. Т.е. здесь подход другой а симптомы похожие.
  5. к сожалению, у нас нет unit-тестов на функционал (пара энтузиастов из нескольких десятков разрабов не в счет). Есть unit-тесты только на ядро. О CI слышали, в курсе, но не применяем.
    Так что часть вероятности несрабатывания тестов можно с чистой совестью отнести к данному обстоятельству.
  6. все, что в моих силах (а я, к сожалению, один пока всем этим занимаюсь) в разумных пределах для улучшения стабильности тестов я сделаю. Всегда буду рад конструктивной критике и разумным предложениям.

(inkvizitorz) #12

4) Ваши бы слова да моему руководству в уши. К огромному сожалению, это не просто приложение, а это если по простому выразится - целый комплекс систем и функционала, которые в разработке больше 15 лет и имеют хренову тьму версий и вариантов. Соответственно, можете прикинуть человеко- часы, если кол-во разрабов в среднем за этот период где-то больше 50 человек.

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

Вопрос про смену драйвера - на сайте есть тема, нельзя ли мысли, высказанные там, адаптировать для моего случая? Если да, то что нужно поменять?
Тема вот


(Дмитрий Мирошник) #13

Есть 2 варианта:
1). Ошибка в приложении. В таком случае проверить вручную, если повторяется - оформить дефект и дальше писать тесты с учётом этого дефекта.
2). Ошибка в тестах. Например, между состоянием кнопки visible и enabled проходит некоторое время. То есть, кнопка браузером отрендерена, но события обрабатывать ещё не может. В этом случае поможет explicit wait.

Я думаю, это то, что Вам нужно. Та же задача: прикрутить инициализацию драйвера перед стартом теста. Методы решения там описаны, дерзайте smile