Переход с Selenium RC на Selenium WebDriver


(Mykhailo Poliarush) #1

Как перейти на Selenium WebDriver

Обычным вопросом, в связи с началом использования Selenium 2 является следующий: «Что делать при добавлении новых тестов к уже существующему набору тестов?». Пользователи, которые начали пользоваться этим фреймворком недавно, могут начать использовать новый WebDriver API для написания тестов. Но как быть тем, у которых уже существуют значительные собственные наработки? Это руководство разработано специально для того, чтобы продемонстрировать, как можно переместить ваши тесты на новые API, давая возможность писать все новые тесты, используя новые возможности, предлагаемые WebDriver.

Способ, описанный здесь, предусматривает частичный постепенный переход к WebDriver APIs без необходимости делать один большой рывок и переделывать все сразу. Это означает, что у вас будет много времени на то, чтобы переместить все ваши уже существующие тесты, благодаря чему, вы сможете наиболее эффективно распределить свои усилия.

Это руководство написано при использовании Java потому, что именно так можно наиболее эффективно провести процесс миграции. Так как мы предлагаем инструменты и для других языков, это руководство будет расширено и включит в себя и эти языки.

Зачем переходить к использованию WebDriver

Перенос набора тестов с одного API на другой требует необычайных усилий. Так зачем вам лично и вашей команде рассматривать такие изменения? Далее указаны несколько причин, по которым, вы, возможно захотите совершить такое перемещения тестов Selenium и использование WebDriver.

  1. Меньший, более компактный API. API у WebDriver более объектно-ориентированный чем у Selenium RC. Благодаря этому с ним намного проще работать.
  2. Лучшая имитация взаимодействия пользователя с системой. При возможности, WebDriver использует собственные случаи для взаимодействия с веб страницей. Это намного лучше имитирует способ, с помощью которого пользователи работают с ваши сайтом и приложениями. Кроме того, WebDriver предлагает усовершенствованные API взаимодействия, которые позволяют Вам моделировать сложные взаимодействия со своим сайтом.
  3. Поддержка браузера. Opera, Mozilla и Google активно участвуют в развитии WebDriver, и у каждого из них есть инженеры, работающие над улучшением фреймворка. Часто, это означает, что поддержка WebDriver подразумевается непосредственно в браузере: ваши тесты, работают настолько быстро и стабильно, насколько это возможно.

Перед тем как начать

Чтобы сделать процесс перемещения максимально безболезненным , удостоверьтесь, что все Ваши тесты работают с последней версией Selenium должным образом. Это может казаться очевидным, но лучше еще раз это повторить!

Начинаем

Первым шагом в начале перемещения является изменение того, как вы получаете свою копию Selenium. Используя Selenium RC, это нужно делать следующим образом:

Selenium selenium = new DefaultSelenium(
    "localhost", 4444, "*firefox", "http://www.yoursite.com");
selenium.start();

И это необходимо заменить следующим : 

WebDriver driver = new FirefoxDriver();
Selenium selenium = new WebDriverBackedSelenium(driver, "http://www.yoursite.com");

После того, как только вы это сделали, запустите ваши уже существующие тесты. Это даст вам возможность оценить необходимый объем работы. Эмуляция Selenium хороша, но не безупречна, так что присутствие некоторых «шероховатостей» и отклонений абсолютно нормально.

Следующие шаги

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

Если вам необходимо извлечь основное выполнение WebDriver из Selenium, вы можете просто использовать WrapsDriver:

WebDriver driver = ((WrapsDriver) selenium).getWrappedDriver();

Это позволяет Вам продолжать передавать Selenium как обычно, распаковав WebDriver как это требуется.

В некоторый момент ваша база кодов будет использовать главным образом более новые API. В этом пункте Вы можете изменить отношения, используя везде WebDriver и проводить обработку с помощью Selenium по требованию:

{syntaxhighlighter brush: bash;fontsize: 100; first-line: 1; }Selenium selenium = new WebDriverBackedSelenium(driver, baseUrl);{/syntaxhighlighter}

Типичные проблемы

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

Клики и печать более совершенны

Обычный пример теста в Selenium RC будет выглядеть приблизительно следующим образом:

selenium.type("name", "exciting tex");
selenium.keyDown("name", "t");
selenium.keyPress("name", "t");
selenium.keyUp("name", "t");

Это основано на том, что «печать» (“type”) просто заменяет содержание идентифицированного элемента без запуска всех событий, которые были бы запущены, если бы пользователь взаимодействовал со страницей. Финальная прямая активизация «ключа» “key*” приводит к тому, что программы обработчики JS запускаются как это и ожидалось .

При использовании WebDriverBackedSelenium, результатом заполнения поля формы будет “exciting texttt”: не то, чего вы ожидали! Причиной этого является то, что WebDriver более точно эмулирует поведение пользователя, и таким образом, он все время запускал события.

Этот же факт может иногда быть причиной того, что загрузка страницы запускается раньше, чем это было бы в тестах Selenium 1. Вы можете сказать, что это случилось если “StaleElementException” переключается WebDriver.

WaitForPageToLoad Returns Too Soon

Определение завершения загрузки страницы довольно непростая задача. Мы имеем ввиду: “когда запускается событие загрузки”, “когда все запросы AJAX завершены”, “когда нет траффика сети”, “когда изменился document.readyState ” или что-то еще?

WebDriver пытается моделировать изначальное поведение Selenium, но, по различным причинам, это не всегда работает отлично. Наиболее распространенная причина состоит в том, что трудно определить различие между загрузкой страницы, которая еще не началась, и загрузкой страницы, закончившейся между вызовами метода. Это иногда означает, что контроль вернулся к Вашему тесту прежде, чем страница закончила (или даже начала!) загрузку.

Решение этого состоит в том, чтобы подождать чего-то определенного. Обычно, это может быть следующий элемент, с которым Вы хотите взаимодействовать, или некоторой переменной Javascript, которой будет установлено определенное значение. Пример был бы:

Wait<WebDriver> wait = new WebDriverWait(driver, 30);
WebElement element= wait.until(visibilityOfElementLocated(By.id("some_id")));
{/syntaxhighlighter}</p><p>где “visibilityOfElementLocated” применяется как :</p><p>{syntaxhighlighter brush: java;fontsize: 100; first-line: 1; }public ExpectedCondition&lt;WebElement&gt; visibilityOfElementLocated(final By locator) {
  return new ExpectedCondition&lt;WebElement&gt;() {
    public WebElement apply(WebDriver driver) {
      WebElement toReturn = driver.findElement(locator);
      if (toReturn.isDisplayed()) {
        return toReturn;
      }
      return null;
    }
  };
}

Это может выглядеть сложным, но это практически шаблонный код. Единственное, что интересно - “ExpectedCondition” будет неоднократно оцениваться, пока "apply" метод не вернет что-то, не являющееся ни "null", ни Boolean.FALSE.

Конечно же, добавление этих “wait” запросов может засорить ваш код. Если дело в этом и ваши потребности просты, рассмотрите возможность использовать скрытые ожидания:

driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

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

Поиск XPath или CSS Selectors не всегда работает, но работает в Selenium 1

В Selenium 1, xpath было свойственно пользоваться связанной библиотекой, а не непосредственно возможностями браузера. WebDriver будет всегда использовать методы браузера, кроме случаев, отсутствия другой альтернативы. Это означает, что комплексные выражения xpath могут повредиться на некоторых браузерах..

CSS Selectors в Selenium 1 выполнялись при использовании библиотеки Sizzle. Таким образом выполняется большое количество спецификаций CSS Selector , и не всегда понятно где именно вы пересекли черту. Если вы используете WebDriverBackedSelenium и используете Sizzle locator вместо CSS Selector для поиска элементов, на ПК управления будет записано предупреждение. Стоит потратить время и обратить внимание на это, особенно, если тесты не выполняются из-за невозможности найти элемент.

Отсутствие Browserbot

Selenium RC бы основан на Selenium Core, и, таким образом, когда вы выполняли Javascript, вы могли получать доступ к сведениям Selenium Core, чтобы все упростить. Так как WebDriver не основан на Selenium Core, такой возможности больше нет. Как вы можете сказать, используете ли вы Selenium Core? Просто! Просто посмотрите на то, используют ли ваши “getEval” или похожие на них запросы “selenium” или “browserbot” в оцениваемом Javascript.

Вы могли бы использовать browserbot, чтобы получить маркер к текущему окну или документу теста. К счастью, WebDriver всегда оценивает JS в контексте текущего окна, таким образом, Вы можете использовать "окно" или "документ" непосредственно

Альтернативно, Вы могли бы использовать browserbot, для местоположения элементов. В WebDriver идиома для того, чтобы сделать это должна сначала определить местоположение элемента, и затем передать это как параметр Javascript. Таким образом:

String name = selenium.getEval(
    "selenium.browserbot.findElement('id=foo', browserbot.getCurrentWindow()).tagName");

становится:

WebElement element = driver.findElement(By.id("foo"));
String name = (String) ((JavascriptExecutor) driver).executeScript(
    "return arguments[0].tagName", element);
{/syntaxhighlighter}</p><p>Обратите внимание как  переданная  переменная "элемента" появляется как первый элемент в стандартном массиве "параметров" JS.</p><h2>Выполнение  Javascript ничего не дает </h2><p>JavascriptExecutor WebDriver вернет весь JS и оценит его как анонимное выражение. Это означает, что Вы должны использовать ключевое слово "return":</p><p>{syntaxhighlighter brush: java;fontsize: 100; first-line: 1; }String title = selenium.getEval("browserbot.getCurrentWindow().title");{/syntaxhighlighter}</p><p>становится:</p><p>{syntaxhighlighter brush: java;fontsize: 100; first-line: 1; }((JavascriptExecutor) driver).executeScript("return window.title;")