0,0
рейтинг
12 сентября 2014 в 11:25

Разработка → Автоматизированное тестирование — это просто! Как я тестировал Печкина из песочницы

Не так давно стал посматривать в сторону Selenium WebDriver, который в связке с PageObject становится прекрасным инструментом для автоматизированного тестирования. Те, кто не знаком с Selenuim, могут ознакомиться в этой статье, а здесь можно прочесть конкретно про Selenium WebDriver.

При написании этой статьи были использованы:
  1. Maven
  2. TestNG
  3. Selenium WebDriver
  4. PageObject
  5. Подопытный кролик: pechkin-mail.ru


Настройка окружения


1. Необходимо установить JDK. Его можно взять с официального сайта — http://www.oracle.com
2. Установить инструмент сборки, мне больше по душе Maven.
Инструкция по установке Maven
Скачиваем последнюю версию Maven с оф. сайта
Распаковываем в любую директорию, например в C:\Program Files\maven\
Добавляем переменную окружения: M2_HOME=C:\Program Files\maven\ и в PATH добавляем %M2_HOME%\bin
Проверим, что все сделано верно:
mvn -version

Должно показать версию Maven'a
Apache Maven 3.2.3 (33f8c3e1027c3ddde99d3cdebad2656a31e8fdf4; 2014-08-12T00:58:10+04:00)
Maven home: C:\Program Files\maven
Java version: 1.8.0_20, vendor: Oracle Corporation
Java home: C:\Program Files\Java\jdk1.8.0_20\jre
Default locale: ru_RU, platform encoding: Cp1251
OS name: "windows 7", version: "6.1", arch: "amd64", family: "dos"


3. В качестве архитектурного решения мы будем использовать архитип Алексея Баранцева (barancev). Заберем архитип с github'a
git clone git://github.com/barancev/webdriver-java-quickstart-archetype.git

Перейдем в папку с архитипом и установим его
cd webdriver-java-quickstart-archetype
mvn install

Следующим шагом будет создание проекта, это мы сделаем командой:
mvn archetype:generate -DarchetypeGroupId=ru.stqa.selenium -DarchetypeArtifactId=webdriver-java-quickstart-archetype -DarchetypeVersion=0.7 -DgroupId=ru.mail.pechkin -DartifactId=PechkinFuncTest

где ru.mail.pechkin — id создаваемого проекта, PechkinFuncTest — артефакт id создаваемого проекта

Вперед к практике!


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

Отредактируем pom.xml:
Будем использовать последнюю версию Selenium WebDriver
<dependency>
			<groupId>org.seleniumhq.selenium</groupId>
			<artifactId>selenium-java</artifactId>
			<version>2.42.2</version>
</dependency>

Остается в application.properties указать URL сайта и браузер, в котором будет происходить тестирование.
site.url=http://pechkin-mail.ru/
browser.name=firefox

Лирическое отступление

Прежде чем начнем писать код, необходимо познакомиться с PageObject. Грубо говоря, PageObject — это шаблон проектирования, который разделяет высокоуровневую логику от низкоуровневой логики поиска и использования элементов интерфейса, при этом повышается читаемость и поддержка кода.

В результате получается отдельный класс, описывающий, в нашем случае, конкретную страницу (WebElement'ы), а так же способы взаимодействия с ними.

Приступим

В ru.mail.pechkin.pages создаем RegistrationPage.java. Это и будет наш шаблон страницы регистрации. Начнем описывать поля. Как было сказано выше, мы имеем:
1. Четыре текстовых поля:
private WebElement emailField;
private WebElement usernameField;
private WebElement passwordField;
private WebElement inviteField;

2. Два чекбокса:
private WebElement dogovorCheckbox;
private WebElement persCheckbox;

3. Кнопку регистрации:
private WebElement submitButton;

Вооружившись инспектором кода, определяем локаторы этих элементов. Наш объект будет выглядеть следующим образом:
@FindBy(id = "email")
private WebElement emailField;
@FindBy(id = "username")
private WebElement usernameField;
@FindBy(id = "password")
private WebElement passwordField;
@FindBy(id = "invite")
private WebElement inviteField;
@FindBy(id = "dogovor")
private WebElement dogovorCheckbox;
@FindBy(id = "pers")
private WebElement persCheckbox;
@FindBy(id = "reg_submit")
private WebElement submitButton;

Следующим шагом будет создание методов, через которые мы будем работать со страницей
public RegistrationPage setEmail(String email){
    emailField.sendKeys(email);
    return this;
}
public RegistrationPage setUsername(String username){
    usernameField.sendKeys(username);
    return this;
}
public RegistrationPage setPassword(String password){
    passwordField.sendKeys(password);
    return this;
}
public RegistrationPage setInvite(String invite){
    inviteField.sendKeys(invite);
    return this;
}
public RegistrationPage setDogovor() {
    if(!dogovorCheckbox.isSelected()) {
        dogovorCheckbox.click();
    }
    return this;
}
public RegistrationPage setPersonal() {
    if(!persCheckbox.isSelected()) {
        persCheckbox.click();
    }
    return this;
}
public void clickSubmitButton() {
    submitButton.click();
}

Еще нам понадобится отслеживать сообщение ошибки при вводе не корректного email.
@FindBy(id = "error_block")
private WebElement errorText;

public boolean isError() {
    if(errorText.isDisplayed()) {
        return true;
    } else {
        return false;
    }
}

RegistrationPage.java
package ru.mail.pechkin.pages;

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class RegistrationPage extends AnyPage{

    @FindBy(id = "reg_submit")
    private WebElement submitButton;

    @FindBy(id = "email")
    private WebElement emailField;

    @FindBy(id = "username")
    private WebElement usernameField;

    @FindBy(id = "password")
    private WebElement passwordField;

    @FindBy(id = "invite")
    private WebElement inviteField;

    @FindBy(id = "dogovor")
    private WebElement dogovorCheckbox;

    @FindBy(id = "pers")
    private WebElement persCheckbox;

    @FindBy(id = "error_block")
    private WebElement errorText;

    public RegistrationPage(PageManager pages) {
        super(pages);
    }

    public RegistrationPage setEmail(String email){
        emailField.sendKeys(email);
        return this;
    }

    public RegistrationPage setUsername(String username){
        usernameField.sendKeys(username);
        return this;
    }

    public RegistrationPage setPassword(String password){
        passwordField.sendKeys(password);
        return this;
    }

    public RegistrationPage setInvite(String invite){
        inviteField.sendKeys(invite);
        return this;
    }

    public RegistrationPage setDogovor() {
        if(!dogovorCheckbox.isSelected()) {
            dogovorCheckbox.click();
        }
        return this;
    }

    public RegistrationPage setPersonal() {
        if(!persCheckbox.isSelected()) {
            persCheckbox.click();
        }
        return this;
    }

    public void clickSubmitButton() {
        submitButton.click();
    }

    public boolean isError() {
        if(errorText.isDisplayed()) {
            return true;
        } else {
            return false;
        }
    }
}


Теперь нам потребуется тот, кто будет управлять нашей страницей. Добавим в ru.mail.pechkin.logic RegistrationHelper.java. В нем будет всего 3 метода:
Заполнение всех полей корректными значениями, кроме email.
public void setEmailWithValidAllFields(String email) {
    pages.registrationPage.setEmail(email).setUsername(username).setPassword(password);
    pages.registrationPage.setDogovor().setPersonal();
}

Нажатие кнопки регистрации
public void clickRegistration() {
    pages.registrationPage.clickSubmitButton();
}

Проверка отображения сообщения об ошибке
public boolean isError() {
    return pages.registrationPage.isError();
}

RegistrationHelper.java
package ru.mail.pechkin.logic;

public class RegistrationHelper extends DriverBasedHelper implements IRegistrationHelper {

    private final String username = "username";
    private final String password = "passw";

    private ApplicationManager manager;

    public RegistrationHelper(ApplicationManager applicationManager) {
        super(applicationManager.getWebDriver());
        this.manager = applicationManager;
    }

    @Override
    public String getTitle() {
        return driver.getTitle();
    }

    public void setEmailWithValidAllFields(String email) {
        pages.registrationPage.setEmail(email).setUsername(username).setPassword(password);
        pages.registrationPage.setDogovor().setPersonal();
    }

    public void clickRegistration() {
        pages.registrationPage.clickSubmitButton();
    }

    public boolean isError() {
        return pages.registrationPage.isError();
    }
}


Пишем тесты


В директории test ru.mail.pechkin создаем RegistrationPageTest.java. Я покажу, как тестировать email поле, поэтому открываем спецификацию на email поля и по ней составляем тесты. Приведу пару примеров.
Позитивные тесты

@Test
public void validEmailWithLowerAndUpperLetters() {
    app.getNavigationHelper().openRegistrationPage();
    app.getRegistrationHelper().setEmailWithValidAllFields("testEmail@mailinator.com");
    app.getRegistrationHelper().clickRegistration();
    Assert.assertTrue(!app.getRegistrationHelper().isError());
}
@Test
public void validEmailWithNumberInLocalPart() {
    app.getNavigationHelper().openRegistrationPage();
    app.getRegistrationHelper().setEmailWithValidAllFields("1testEmail1@mailinator.com");
    app.getRegistrationHelper().clickRegistration();
    Assert.assertTrue(!app.getRegistrationHelper().isError());
}

Негативные тесты

@Test
public void notValidEmailEmptyField() {
    app.getNavigationHelper().openRegistrationPage();
    app.getRegistrationHelper().setEmailWithValidAllFields("");
    app.getRegistrationHelper().clickRegistration();
    Assert.assertTrue(app.getRegistrationHelper().isError());
}
@Test
public void notValidEmailWithLackOfLocalPart(){
    app.getNavigationHelper().openRegistrationPage();
    app.getRegistrationHelper().setEmailWithValidAllFields("@mailinator.com");
    app.getRegistrationHelper().clickRegistration();
    Assert.assertTrue(app.getRegistrationHelper().isError());
}

Заключение


На этом и закончим. У меня вышло 37 тестов на проверку email. Негативный тест на проверку двух последовательных точек в локальной части email неожиданно зафейлился, ровно как и превышение количества символов в локальной части.
Павел Скворцов @SkvPavel
карма
5,0
рейтинг 0,0
QA Engineer
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (19)

  • 0
    А чем это отличается от обычно работы с Selenium через создание обычного java файла, импортирования нужных пакетов и написания тех же самых тестов? Без лишних проектов, архетипов.
    • 0
      Тем, что это quickstart с уже готовой архитектурой и зависимостями. Это та работа, которая проделывается при разработке нового проекта, так почему бы это не автоматизировать? ;)
      • 0
        Понятно, спасибо.
  • +1
    Еще Allure прикрутите в качестве отчета и будет совсем удобно.
    • 0
      Конечно, следующая статья будет посвящена HTML Elements и Allure.
  • +1
    У меня вышло 37 тестов на проверку email

    Реальный проект очень быстро поставит на место. Абсолютно нереально покрывать каждое поле 37 тестами. Это мало того, что не очень быстро в плане времени разработки, но это еще пол беды. Большое количество таких Selenium тестов делает время билда ну слишком большим, нереально большим для многих проектов. И еще большое кол-во Selenium тестов имеет тенденцию падать в рандомных местах, поэтому практически нереально становится добиться зеленого билда даже если у нас все работает.
    • 0
      В таком случае можно сгруппировать тесты по разному уровню важности/потенциальной стоимости исправления, критичные тесты проводить всегда автоматизированно и в фоне после каждой промежуточной сборки, финальный билд в таком случае выглядел бы как доводка незначительных проблем/тестов среднего и менее уровня важности.

      Да, такое разделение реализовать достаточно сложно, долго и дорого. Но это действительно полезно для больших, долгоживущих проектов.
      • 0
        Вы молодец, что освещаете эту тему. Я занимался автоматизацией тестирование на большущем проекте. И знаете к какому выводу я пришел? Если можно без Селениума — лучше без него. К сожалению, драйвера еще очень глючные и с каждым обновлением браузера, надо обновлять версию драйвера. Как ни печально, m00t прав.
        • +1
          Я для себя решил так: по возможности (если не сильно много JS на страницах) использовать для таких тестов не реальный браузер, а просто curl. И только на тех сценариях, которые юзают JS, подключать реальный браузер через Selenium (или phantomjs). Ну и не стоит забывать про остальные более быстрые и дешевые тесты, не тестирующие непосредственно UI.
          • 0
            использовать для таких тестов не реальный браузер, а просто curl

            А можно пример для запуска теста на нескольких версиях браузера в параллель?
            • 0
              Не совсем понял, о каком примере идет речь. Поясню, что я имею ввиду. Скажем, у нас есть форма логина без всякого JS. Нету смысла запускать реальный браузер для того, чтобы протестировать работает она или нет. Достаточно сделать GET CURL запрос на /login, прочитать все данные из нужной <form>, отправить правильно сформированный POST запрос с этими данными на какой-нибудь /login_check (или как там где), проверить наличие нужной строки в полученном HTML (например «You are logged in as Username» или «Wrong credentials»). Для таких вещей нету необходимости запускать этот тест в 5 версиях разных браузеров.
              • 0
                может уж лучше тогда HtmlUnit использовать для этого?
                т.е., если вам не нужно тестирование именно UI части, то вполне достаточно протестировать логику на странице с помощью HtmlUnit.
                • +1
                  Я работаю не в Java стеке, поэтому не знаю что такое HtmlUnit. У нас в PHP есть отличная абстракция над браузером — Mink. Он позволяет абстрагироваться от реального драйвера веб-браузера и оперировать такими понятиями как «кликнуть на этой кнопке», «ввести это в поле», «найти на странице такую-то надпись», «перейти по такому-то URL» и т.д. А внутри в зависимости от нужд может быть драйвер либо Selenium (или phantomjs), либо обычный CURL (+ libxml для обработки xpath). В одном и том же тест-сюите могут быть рядом и JS тесты, и такие тесты через CURL, нужно только подменять драйвер на тот, который нужен в конкретном сценарии.
        • 0
          Да, естественно, если суть теста напрямую не связана с проверкой клиентского функционала в браузерах — то это не нужно делать с помощью селениума. Тот же PHPUnit, ScalaTest, хоть curl в bash-скрипте — вполне рабочее решение. Выбор в зависимости от принятых инструментов тестирования в проекте. Я с moot не спорил, просто предложил один из вариантов реорганизации тестов по уровням, т.к. считаю что со временем от большого количества тестов не уйти — это неизбежно. Можно тесты рефакторить время от времени, но и это тоже до определенной степени только сможет помочь. Рост уникального функционала -> рост числа тестов, любой развивающийся проект с грамотным сопровождением будет этому подвержен.
          • 0
            С большим кол-вом UI тестов да, многие описанные вами подходы помогут. Другое дело, что по возможности стоит все-таки стараться не делать огромное кол-во этих UI браузерных тестов. Например «37 тестов на проверку email» это явно не то, для чего надо запускать Selenium (по моему мнению).
  • 0
    Будем использовать последнюю версию Selenium WebDriver

    2.43 последняя
    • 0
      На момент написания статьи была именно та, которая указана в статье.
      • –2
        <зануда мод> 9-10 сентября</зануда мод>
        • 0
          [зануда мод] написание статьи != публикация статьи [/зануда мод]

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