t.me/atinfo_chat Telegram группа по автоматизации тестирования

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

Теги: #<Tag:0x00007f9b09b42408> #<Tag:0x00007f9b09b42340> #<Tag:0x00007f9b09b42228> #<Tag:0x00007f9b09b42160> #<Tag:0x00007f9b09b41fd0> #<Tag:0x00007f9b09b41f08>

Есть определенный набор тестов, принадлежащей одной 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 использует результат теста 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 для каждой из частей стори.

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 (конец этого года примерно, кода наберется много тестов).

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

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

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

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

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

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

Так-с.

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

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

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

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

  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. большое спасибо за ответ. Но мне очень важно сейчас все-таки найти альтернативное решение по смене драйвера во время выполнения. Разбиение на несколько стори не подходит, так как их кол-во сразу увеличится в несколько раз и, кроме того, между ними придется передавать параметры и запускать в строго определенной последовательности.

Я просто решу задачку по терверу за второй курс матфака.
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

1 Симпатия

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: инициализировать драйвер не мавеном, а для каждого теста отдельно внутри самого теста. В конструкторе класса, от которого наследуются Ваши тесты, пропишите инициализировать драйвер необходимым типом браузера. Для наглядности можно запхать тип браузера во внешний файл или пробросить в какой-нить аннотации.
Не забудьте к конце теста выгружать его во избежание утечек памяти ))

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

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

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

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

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

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