Введение в проектирование тестов

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

Разновидности тестов

Какие части вашего приложения следует тестировать? Это зависит от особенностей вашего проекта: пользовательских ожиданий, сроков, выделенных на проект, приоритетов, расставленных вашим проект-менеджером и т. п. Но все же, именно тестировщику предстоит принимать решения о том, что и как тестировать.

Для категоризации видов тестов, подходящих для ваших веб-приложений, мы придумали несколько терминов. Данные термины не являются общепризнанными, однако описываемые здесь методологии широко используются при тестировании веб-ориентированных приложений.

Тестирование статичного контента

Самый простой вид тестирования - “контентное”. Это простой тест, который проверяет существование статичного, т. е. не изменяющегося элемента пользовательского интерфейса. Например:

  • Правильно ли озаглавлены страницы? Эту проверку можно использовать для того, чтобы удостовериться в том, что тест обнаружил искомую страницу после перехода по ссылке.
  • Содержит ли главная страница нужную картинку сверху?
  • Расположена ли контактная информация, описание политики конфиденциальности и информация о торговой марке в подвале страницы?
  • Стоит ли в начале каждой страницы заголовок с тэгом <h1> Содержит ли этот заголовок верный текст?

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

Тестирование ссылок

Битые ссылки являются частым источником ошибок на веб сайтах. Тестирование подразумевает переход по каждой ссылке и проверку того, что выдана ожидаемая страница. Если статичные ссылки редко меняются, то достаточно будет ручного тестирования. Однако если ваши веб-дизайнеры часто переделывают ссылки, или же файлы периодически перемещаются, то тестирование ссылок следует автоматизировать.

Тестирование функциональности

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

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

Тестирование динамических элементов

Зачастую веб-элемент обладает уникальным идентификатором, который дает возможность найти этот элемент на странице. Обычно такие идентификаторы реализованы с помощью HTML атрибутов ‘id’ или ‘name’. Эти значения могут быть как статичными — т. е. неизменяемыми строковыми константами, так и динамически генерируемыми значениями, отличающимися на разных страницах сайта. Например, некий веб-сервер может отображать имя документа как “doc3861” на одной странице, и как “doc6148” на другой, в зависимости от того, какой документ запрашивает пользователь. Это означает, что вашему тестовому скрипту, проверяющему, был ли документ создан правильно, может быть недоступен постоянный соответствующий документу идентификатор. Зачастую страница с какой-либо выдачей, зависящей от действий пользователя, содержит динамические элементы с меняющимися идентификаторами. Впрочем, конкретная реализация, безусловно, зависит от работы веб-приложения.

Например:

<input type="checkbox" value="true" id="addForm:_ID74:_ID75:0:_ID79:0:
 checkBox"/>

Здесь приведен HTML-код для чек-бокса, id которого (addForm:_ID74:_ID75:0:_ID79:0:checkBox), является динамически генерируемым значением. Когда эту же страницу откроют в следующий раз, значение id, вероятно, будет другим.

Тестирование AJAX

AJAX - это технология, поддерживающая динамическое изменение элементов пользовательского интерфейса без перезагрузки страницы. Это, например, может быть анимацией, RSS-лентой или обновлением данных в режиме реального времени. Существует несметное количество способов использования AJAX для обновления веб-элемента на странице. Проще всего это можно описать следующим образом: в AJAX-ориентированных приложениях данные, передаваемые сервером, затем отображаются на странице без ее перезагрузки, обновляется только ее часть или же непосредственно измененный элемент.

Проверка результатов

Assert или Verify?

Когда следует использовать команду assert, а когда лучше использовать verify? Решать вам, в зависимости от желаемого поведения в случае, если результат проверки окажется отрицательным: хотите ли чтобы тест был остановлен или чтобы продолжил работу, записав сообщение об ошибке.

Какие же плюсы и минусы? Если вы используете assert, то при обнаружении ошибки тест остановится, и последующие проверки запускаться не будут. В некоторых случаях, а иногда и в большинстве, это то, что нужно. Если тест не проходит, вы тут же узнаете, что результат теста отрицательный. У большинства тестовых фреймворков, таких как TestNG и JUnit, есть расширения для наиболее распространенных сред разработки (Глава 5), которые условно помечают такие тесты, как проваленные. Преимущества: вы сразу же видите результат проверки. Недостатки: когда тест останавливается, в самом нем остаются не выполненные проверки, результат которых вы узнать не сможете.

Команда verify, напротив, не завершает выполнение теста. Если ваш тест состоит только из таких проверок, то тест гарантированно (если допустить, что не произойдет неожиданных ошибок) будет исполнен, вне зависимости от того, будут ли обнаружены дефекты или нет. Недостатки: необходимо тратить больше усилий на проверку результатов тестирования. TestNG и JUnit уже не будут предоставлять вам дополнительную информацию. Вам придется отслеживать результаты выполнения тестов в консоли или в логах. Причем делать это каждый раз, когда вы запускаете свой тест. Если у вас сотни тестов, и у каждого из них свой лог, это будет отнимать очень много времени. Поэтому из-за возможности мгновенной выдачи результата тестирования, команда assert используется чаще команда verify.

Плюсы и минусы: assertTextPresent, assertElementPresent, assertText ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Эти три команды и способы их использования уже должны быть вам знакомы, если нет, сначала изучите главу 3. Создавая свои тесты, вам необходимо решить:

  • Следует ли проверить только то, что текст на странице существует? (verify/assertTextPresent)
  • Следует ли проверить только то, что на странице существует элемент HTML? Это значит, что текст, изображение или любой другой контент не проверяются, и нас лишь

интересует наличие тэга HTML. (verify/assertElementPresent) - Необходимо ли тестировать и элемент и текст, который он содержит? (verify/assertText)

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

Verify/assertText - наиболее точная проверка. Она будет срабатывать в обоих случаях, когда либо HTML-элемент, либо его содержимое не соответствуют вашему ожидаемому результату.

Допустим, что ваша страница подвержена регулярным изменениям, и ваши веб-дизайнеры постоянно переписывают ее код. Вы не хотите, чтобы ваши тесты отказывали каждый раз, когда меняется страница, однако вам все же следуют проверять, что на странице присутствует необходимый элемент, например параграф, текст заголовка или картинка. В таком случае рекомендуется использовать verify/assertElementPresent. Это позволит проверить, что элемент определенного типа на странице существует (а используя XPath вы можете проверить не только то, что этот элемент существует, но и его расположение относительно других элементов на странице). Однако вас не интересует содержание данного элемента. Другими словами, вам важно, что на странице в определенном месте отображается определенный элемент, скажем, изображение.

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

Методы поиска элементов

Выбор стратегии поиска элемента

Существует несколько способов выбора объект на странице. Но какие же плюсы и минусы у каждого из них? Как вы помните, мы можем найти объект с помощью:

  • атрибута ID
  • атрибута name
  • выражения XPath
  • по тексту ссылки
  • DOM-модели

С точки зрения производительности, использование поиска по атрибутам ID или name наиболее эффективно. К тому же, это позволяет сделать ваши тесты более читаемыми (при условии так же читаемых в коде страницы значений этих атрибутов).

Обработка XPath выражения требует больше времени, так как браузеру необходимо запускать его XPath обработчик. Особенно медленно XPath работает в браузере Internet Explorer версии 7. Нахождение элементов по тексту ссылки зачастую очень быстрое и удобное, однако, применимо только к ссылкам. К тому же, если сами ссылки регулярно изменяются, поиск по тегу <a> бдует значительно удобнее.

И все же, иногда исходный код не содержит атрибуты ID или name и тогда у вас не остается другого выбора, кроме как использовать поиск по XPath. (Поиск по DOM-модели в основном поддерживается для обеспечения совместимости со старыми тестами, и обычно уже не используются, т. к. XPath может делать все то же самое и даже больше.)

Однако у XPath есть и преимущество перед поиском по ID или name. С помощью XPath (и DOM) вы можете найти элемент относительно расположения других элементов на этой странице. Например, вам необходимо проверить, что данная ссылка находится во втором параграфе текста, внутри секции <div>. Это можно задать при помощи XPath. При использовании локаторов ID и name, можно проверить лишь факт наличия элемента на странице вообще, без указания определенного местоположения. Так что если вам нужно проверить, что логотип компании отображается наверху сайта, в секции <header>, то следует использовать локатор XPath.

Поиск динамических элементов

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

<a class="button" id="adminHomeForm" onclick="return oamSubmitForm('adminHomeForm',
 'adminHomeForm:_ID38');" href="#">View Archived Allocation Events</a>

Данный HTML-тег описывает кнопку, с ID атрибутом “adminHomeForm”. По сравнению с большинством элементов HTML, данный тег относительно сложный, однако он все же является статичным тегом. Данный код будет одинаковым, каждый раз, когда браузер загружает страницу. ID будет оставаться постоянным от страницы к странице. Поэтому у этого элемента пользовательского интерфейса всегда будет свой идентификатор, и чтобы нажать на кнопку, вам достаточно воспользоваться простой командой:

click       adminHomeForm

Или при использовании Selenium 1.0

selenium.click("adminHomeForm");

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

<input type="checkbox" value="true" id="addForm:_ID74:_ID75:0:_ID79:0:checkBox"
    name="addForm:_ID74:_ID75:0:_ID79:0:checkBox"/>

Это описание чек-бокса. Атрибуты ID и name (addForm:_ID74:_ID75:0:_ID79:0:checkBox) - динамически генерируемые значения. В этом случае при использовании стандартного локатора, код выглядел бы так:

click       addForm:_ID74:_ID75:0:_ID79:0:checkBox

В Selenium-RC

selenium.click("addForm:_ID74:_ID75:0:_ID79:0:checkBox);

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

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

click       //input

Или же, если это не самый первый элемент ввода на странице (что наиболее вероятно), конкретизируйте ваше условие XPath:

click       //input[3]

Или

click       //div/p[2]/input[3]

Если же вам во что бы то ни стало нужно искать элемент по атрибуту ID, можно использовать другое решение. Можно захватить ID со страницы перед использованием в команде Selenium. Делается это следующим образом:

String[] checkboxids  = selenium.getAllFields(); // Collect all input IDs on page.
             for(String checkboxid:checkboxids) {
                    if(checkboxid.contains("addForm")) {
                selenium.click(expectedText);
            }
             }

Данный подход будет работать, если на вашей странице только один чек-бокс, к атрибуту ID которого добавлен ‘expectedText’.

Поиск AJAX элементов

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

Лучше всего с обнаружением и проверкой AJAX элементов на странице справляется Selenium 2.0 WebDriver API. Он был специально спроектирован с учетом необходимости тестирования AJAX элементов, и именно в этой области у Selenium 1 существует ряд ограничений.

В Selenim 2.0 существует метод waitFor(), который ожидает загрузки элемента страницы. В этот метод передается параметр - объект класса “By”, с помощью которого в WebDriver реализованы локаторы. Подробное объяснение вы можете найти в главах посвященных WebDriver.

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

Давайте представим сайт, на котором по щелчку мыши (без полной перезагрузки страницы) появляется ссылка (link=AJAXLink).

Код проверки этой ссылки в Selenium с использованием цикла выглядит так:

// Начало цикла
for (int second = 0;; second++) {

     // Если цикл уже исполняется дольше 60 секунд, то прервать цикл
     if (second >= 60) break;

     // Искать элемент "link=AJAXLink", если найден, то прервать цикл
     try { if (selenium.isElementPresent("link=AJAXLink")) break; } catch (Exception e) {}

     // Пауза в 1 секунду
     Thread.sleep(1000);

}

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

“Обертки” вызовов Selenium

В любом языке программирования вы будете стараться избегать дублирования кода, используя содержащие его служебные функции. Одним из способов сделать это - ”обернуть” часто используемые вызовы в функции или собственные методы. Например, во множестве тестов нужно кликнуть на элемент страницы и подождать пока она обновится.

selenium.click(elementLocator);
selenium.waitForPageToLoad(waitPeriod);

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

/**
 * Нажимает на элемент и ждет пока страница загрузится
 *
 * параметры: Локатор элемента и время ожидания
 *
 param elementLocator
 * param waitPeriod
 */
public void clickAndWait(String elementLocator, String waitPeriod) {
        selenium.click(elementLocator);
        selenium.waitForPageToLoad(waitPeriod);
}

“Безопасные операции” на существующих элементах

Другой распространенный пример использования оберток для методов Selenium - проверка наличие элемента на странице перед совершением над ним действий. Это называется “безопасной операцией”. Например:

/**
 * Selenum-RC -- Кликает на элемент, если он доступен на странице
 *
 * param elementLocator
 */
public void safeClick(String elementLocator) {
        if(selenium.isElementPresent(elementLocator)) {
                selenium.click(elementLocator);
        } else {
                // Используем TestNG API для логирования
                Reporter.log("Element: " +elementLocator+ ", is not available on page - "
                                +selenium.getLocation());
        }
}

В данном примере используется Selenium 1 API, но в Selenium 2 так же поддерживается данная функциональность.

/**
 * Selenium-WebDriver -- Кликает на элемент, если он доступен на странице
 *
 * param elementLocator
 */
public void safeClick(String elementLocator) {
        WebElement webElement = getDriver().findElement(By.XXXX(elementLocator));
        if(webElement != null) {
                selenium.click(elementLocator);
        } else {
                // Используем TestNG API для логирования
                Reporter.log("Element: " +elementLocator+ ", is not available on page - "
                                + getDriver().getUrl());
        }
}

В этом примере, вместо ‘XXXX’ следует использовать один из множества методов для поиска элементов страницы.

Использовать “безопасный метод” следует по усмотрению тестировщика. Если необходимо, чтобы выполнение теста продолжилось даже при отсутствии элемента на странице, то можно использовать “безопасный метод”, совместно с логированием сообщения о несуществующем элементе. Конечно же такая реализация подразумевает использование проверки ‘verify’, вместо прерывающей тест ‘assert’. Но если элемент необходим для осуществления дальнейших действий (например, кнопка “войти в систему” на главной странице), то данную технику лучше не применять.

Карта пользовательского интерфейса

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

Что же полезного в карте интерфейса? Ее главная задача - облегчить обслуживание скрипта. Например когда необходимо отредактировать локатор, то гораздо проще найти объект в едином центральном хранилище, чем искать его по всему коду. К тому же, это позволяет редактировать идентификатор в одном месте, а не изменять несколько значений по всему скрипту, или, того хуже, в коде сразу нескольких скриптов.

Подытоживая, можно сказать, что использование карты интерфейса предоставляет два значительных преимущества:

  • вместо того, чтобы разбрасывать по всему коду объекты пользовательского интерфейса, используется централизованное хранилище. Это упрощает последующую поддержку скриптов;
  • позволяет придать генерируемым (зашифрованным) HTML-идентификаторам более удобочитаемые имена, что позволяет улучшить восприятие кода.

Ознакомьтесь со следующим тяжело поддающимся восприятию отрывком Java кода:

public void testNew() throws Exception {
             selenium.open("http://www.test.com");
             selenium.type("loginForm:tbUsername", "xxxxxxxx");
             selenium.click("loginForm:btnLogin");
             selenium.click("adminHomeForm:_activitynew");
             selenium.waitForPageToLoad("30000");
             selenium.click("addEditEventForm:_IDcancel");
             selenium.waitForPageToLoad("30000");
             selenium.click("adminHomeForm:_activityold");
             selenium.waitForPageToLoad("30000");
}

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

public void testNew() throws Exception {
             selenium.open("http://www.test.com");
             selenium.type(admin.username, "xxxxxxxx");
             selenium.click(admin.loginbutton);
             selenium.click(admin.events.createnewevent);
             selenium.waitForPageToLoad("30000");
             selenium.click(admin.events.cancel);
             selenium.waitForPageToLoad("30000");
             selenium.click(admin.events.viewoldevents);
             selenium.waitForPageToLoad("30000");
}

Теперь при помощи нескольких комментариев, отступов и карты интерфейса можно получить легко читаемый скрипт.

public void testNew() throws Exception {

             // Открываем ссылку
             selenium.open("http://www.test.com");

             // Вводим имя пользователя
             selenium.type(admin.username, "xxxxxxxx");

             // Нажимаем на кнопку "Войти в систему"
             selenium.click(admin.loginbutton);

             // Нажимаем на кнопку "Создать событие"
             selenium.click(admin.events.createnewevent);
             selenium.waitForPageToLoad("30000");

             // Нажимаем на кнопку "Отмена"
             selenium.click(admin.events.cancel);
             selenium.waitForPageToLoad("30000");

             // Нажимаем на кнопку "Посмотреть события"
             selenium.click(admin.events.viewoldevents);
             selenium.waitForPageToLoad("30000");
}

Реализовать карту пользовательского интерфейса можно разными способами: сделать отдельный класс или присвоить локаторам отдельные глобальные строковые переменные. В качестве альтернативы можно использовать текстовый файл, содержащий пары ключ-значение. Для языка Java такой файл - наиболее предпочтительный метод.

Рассмотрим файл свойств prop.properties присваивающий локаторам удобочитаемые псевдонимы из предыдущего примера.

admin.username = loginForm:tbUsername
admin.loginbutton = loginForm:btnLogin
admin.events.createnewevent = adminHomeForm:_activitynew
admin.events.cancel = addEditEventForm:_IDcancel
admin.events.viewoldevents = adminHomeForm:_activityold

Все локаторы по прежнему ссылаются на объекты html. Но мы создали уровень абстракции между кодом тестов и элементами пользовательского интерфейса. Все значения считываются из файла и используются в тестовых классах в качестве карта пользовательского интерфейса. Подробнее о файлах свойств в Java вы можете узнать перейдя `по ссылке`_.

Шаблон проектирования “Page Object”

Page Object - это популярный в автоматизированном тестировании шаблон проектирования, который упрощает поддержку написанных тестов и уменьшает количество дублируемого кода. Это объектно-ориентированный класс, который выступает интерфейсом веб-страницы тестируемого приложения. Методы данного класса используются в тесте при взаимодействии с элементами пользовательского интерфейса приложения. Большим преимуществом является то, что при изменении дизайна пользовательского интерфейса, нужно исправлять не сами тесты, а только лишь код внутри класса “Page Object”. Соответственно, все изменения, которые необходимо осуществить для реализации поддержки нового интерфейса будут сосредоточены в одном месте.

Шаблон проектирования “Page Object” обладает следующими преимуществами:

  1. Четкое разделение между непосредственно кодом тестов и зависящего от страницы кода, вроде локаторов (или их применения, если используется карта пользовательского интерфейса, разметка);
  2. Наличие единого репозитория для всех служб и операций, представленных на странице, а не множества разбросанных по всему тестовому набору.

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

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

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

Для начала представьте себе типичный тест, в котором не используется “Page Object”.

/***
 * Тест входа в систему
 */
public class Login {

        public void testLogin() {
                selenium.type("inputBox", "testUser");
                selenium.type("password", "my supersecret password");
                selenium.click("sign-in");
                selenium.waitForPageToLoad("PageWaitPeriod");
                Assert.assertTrue(selenium.isElementPresent("compose button"),
                                "Авторизация не удалась");
        }
}

В данном подходе два недостатка:

  1. Отсутствует разделение кода. И код тестов, и локаторы тестируемого приложения (в данном случае ID) переплетаются в одном методе. Если в вашем приложении изменится пользовательский интерфейс, разметка или способ обработки входа в систему, то данный тест придется переписывать.
  2. Локаторы, ищущие по ID будут разбросаны по всему тестовому набору везде, где используется страница входа в систему.

Данный пример страницы для входа в систему может быть переписан следующим образом с использованием паттерна “Page Object”:

/**
 * Инкапсуляция страницы входа "Page Object"
 */
public class SignInPage {

        private Selenium selenium;

        public SignInPage(Selenium selenium) {
                this.selenium = selenium;
                if(!selenium.getTitle().equals("Sign in page")) {
                        throw new IllegalStateException("Это не страница входа, это: "
                                        +selenium.getLocation());
                }
        }

        /**
 * Войти как пользователь системы
 *
 * @param userName
 * @param password
 * @return HomePage object
 */
        public HomePage loginValidUser(String userName, String password) {
                selenium.type("usernamefield", userName);
                selenium.type("passwordfield", password);
                selenium.click("sign-in");
                selenium.waitForPageToLoad("waitPeriod");

                return new HomePage(selenium);
        }
}

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

/**
 * Инкапсуляция главой страницы "Page Object"
 */
public class HomePage {

        private Selenium selenium;

        public HomePage(Selenium selenium) {
                if (!selenium.getTitle().equals("Личный кабинет пользователя")) {
                        throw new IllegalStateException("Это не домашняя страница пользователя, это:" +
                                        "is: " +selenium.getLocation());
                }
        }

        public HomePage manageProfile() {
                // Инкапсуляция класса для работы с учетной записью пользователя
                return new HomePage(selenium);
        }

        /*Другие методы, которые используются для
 описания функционала главной страницы для зарегестрированных пользователей. Такие методы
 в свою очередь тоже могут возвращать другие "Page Objects". Например клик на кнопку
 "Написать email", может возвращать объект
 класса ComposeMail (для написания email)
 */

}

Теперь тест для входа в систему может быть написан с использованием этих двух классов:

/***
 * Тест функциональности для входа в систему
 */
public class TestLogin {

        public void testLogin() {
                SignInPage signInPage = new SignInPage(selenium);
                HomePage homePage = signInPage.loginValidUser("userName", "password");
                Assert.assertTrue(selenium.isElementPresent("compose button"),
                                "Войти не удалось");
        }
}

Единого стандарта для использования и дизайна объектов страницы (page objects) не существует, однако стоит придерживаться определенных правил для обеспечения простоты поддержки и сопровождения кода для ваших тестов. Объекты страницы (Page objects) никогда не должны осуществлять проверки (verify или assert). Эта часть должна всегда содержаться только в коде ваших тестов. В этом классе должна быть представлена непосредственно страница и сервисы, которые она предоставляет, но никак не код относящийся к тому, что должно проверяться и тестироваться.

Единственная проверка, которую можно (и нужно) включать в код класса “Page Object”, это проверка на то, что страница и важные элементы на ней загрузились корректно. Это проверку нужно осуществлять при инициализации объекта. В выше приведенных примерах конструкторы обоих классов SignInPage и SignInPage проверяют, что ожидаемая страница загрузилась и готова исполнять запросы, которые посылают тесты.

Класс “Page Object” не обязательно должен описывать страницу целиком. Этот шаблон проектирования может использоваться для описания компонентов страницы. Если тестируемое приложение состоит из нескольких компонентов, то использование отдельных объектов страниц для каждого компонента помогает улучшить сопровождаемость тестового набора.

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

Тестирование управляемое данными

Тестированием управляемым данными (DDT, Data Driven Testing) называют такой процесс, когда одинаковый тест выполняется множество раз используя меняющиеся тестовые данные. Подобные наборы данных, как правило, хранятся во внешних файлах (например .csv или текстовый файл) или загружаются из баз данных. Техника тестирования DDT широко используется, когда необходимо проверить, как приложение обрабатывает различные вводимые значения. В таком случае можно легко создавать новые тесты, без изменения кода тестового скрипта, просто добавляя новые варианты данных в файл.

В Python:

# Строковый массив значений из файла
source = open("input_file.txt", "r")
values = source.readlines()
source.close()
# Цикл для вызова функции Поиска, для каждого значения из массива
for search in values:
    sel.open("/")
    sel.type("q", search)
    sel.click("btnG")
    sel.waitForPageToLoad("30000")
    self.failUnless(sel.is_text_present("Results * for " + search))

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

Это очень простой пример, но нам лишь хотелось показать, что, используя язык программирования, очень легко написать тест, который будет выполняться для изменяющихся данных. Для получения более подробной информации просмотрите нашу вики Selenium RC. К тому же тестирование управляемое данными довольно частая тема и среди тех профессионалов автоматического тестирования, которые не используют Selenium. Поэтому вы можете найти множество блогов и форумов по запросу “data-driven testing” .. вики Selenium RC: http://wiki.openqa.org/pages/viewpage.action?pageID=21430298

Проверка базы данных

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

Предположим, что вам нужно найти в базе данных существующий e-mail, и использовать его на сайте через пользовательский интерфейс. Пример установки соединения с базой данных и отправкой запроса, выглядит следующим образом:

В Java:

// Загружаем драйвер Microsoft SQL Server JDBC
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");

// Сохраняем ссылку для соединения
String url = "jdbc:sqlserver://192.168.1.180:1433;DatabaseName=TEST_DB";

// Устанавливаем соединение с базой данных
public static Connection con =
DriverManager.getConnection(url, "username", "password");

// Создаем объект, который будет использоваться
// для DDL и DML SQL запросов.
public static Statement stmt = con.createStatement();

// Отсылаем с помощью метода Statement.executeQuery
// запросы SQL SELECT, которые вернут запрашиваемую
// информацию в объект класса ResultSet

ResultSet result =  stmt.executeQuery
("select top 1 email_address from user_register_table");

// Извлекаем значение "email_address"
String emailaddress = result.getString("email_address");

// Используем полученный emailAddress
// для входа в приложение
selenium.type("userID", emailaddress);
selenium.type("password", secretPassword);
selenium.click("loginButton");
selenium.waitForPageToLoad(timeOut);
Assert.assertTrue(selenium.isTextPresent("Добро пожаловать" +emailaddress), "Не удалось войти, используя " +emailaddress)

Это простой пример извлечения данных из базы для Java.

Спонсоры перевода








Go to top