Как тестировать GMail

Капабилятити!

Блог

Как тестировать GMail

Привет!

Вы когда-нибудь задумывались, а как бы вы стали тестировать GMail, если б были разработчиком Google? Это отличное упражнение для тестировщика, непременно попробуйте!

Тестирование GMail нетривиально, т.к. в нём на каждый чих используется Ajax, грузится долго, всё генерируется динамически и нет разумных селекторов/айдишек. Замучаешься везде проставлять wait!

Проект GMail test

Но счастье возможно! В серии Selenide Examples мы представляем проект на гитхабе, в котором написан тест для GMail. Он проверяет содержимое инбокса и пишет новое письмо. Причём ещё и делает “Undo”, редактирует и снова посылает. И в конце ждёт, пока кнопка “Undo” пропадёт.

Видео

И тут даже есть короткое видео, демонстрирующее, как это работает:

Вскрытие покажет

Вот сам проект на гитхабе: https://github.com/selenide-examples/gmail

Давайте рассмотрим некоторые моменты подробнее.

Настройка

Перед запуском тестов надо увеличить таймаут, т.к. в GMail часто элементы грузятся дольше 4 секунд, которые прописаны в Selenide по умолчанию. Поставим 10 секунд. Хотя на некоторых конференциях, где интернет слабенький, мне и этого не хватало.

  @BeforeClass
  public static void openInbox() {
    timeout = 10000;
    baseUrl = "http://gmail.com";
    
    open("/");
    $(byText("Loading")).should(disappear);
    login();
  }

Обратили внимание, как мы ждём окончания загрузки страницы? В этом вся мощь Selenide: элемент легко найти по тексту, и легко дождаться, пока он пропадёт.

Логин

Логин происходит очень просто:

  private static void login() {
    $("#Email").val(System.getProperty("gmail.username", "enter-your-gmail-username"));
    $("#Passwd").val(System.getProperty("gmail.password", "enter-your-gmail-password"));
    $("#signIn").click();
    $(".error-msg").waitUntil(disappears, 2000);
  }

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

Количество непрочитанных писем

В реальной жизни я бы запускал тесты с определённым набором тестовых данных со, скажем, 4 непрочитанными письмами. И тогда я бы в тесте проверил наличие надписи “Inbox (4)”:

  @Test
  public void showsNumberOfUnreadMessages() {
    $(By.xpath("//div[@role='navigation']")).find(withText("Inbox (4)")).shouldBe(visible);
  }

(Но тут у нас случай сложнее, нам приходится тестировать с реальными данными, которые непостоянны. Поэтому ограничимся просто проверкой наличия слова “Inbox”.)

Проверка содержимого инбокса

Увы, у GMail все локаторы тщательно заобфускированы. Использовать ID или другие селекторы не представляется возможным. Поэтому ограничимся просто проверкой наличия на странице определённых текстов - мы знаем, что такие письма точно должны быть в моём инбоксе:

  @Test
  public void inboxShowsUnreadMessages() {
    $$(byText("Gmail Team")).filter(visible).shouldHave(size(1));
    $$(byText("LastPass")).filter(visible).shouldHave(size(3));
    $$(byText("Pivotal Tracker")).filter(visible).shouldHave(size(3));
  }

Обновление инбокса

В интерфейсе GMail есть кнопка обновления “Refresh”. Ищем её по атрибуту title=Refresh - другого способа я не нашёл.

  @Test
  public void userCanRefreshMessages() {
    // В реальной жизни: INSERT INTO messages ...
    $(by("title", "Refresh")).click();
    // В реальной жизни: проверить, что новое письмо появилось в инбоксе
  }

В настоящих тестах я до нажатия добавил бы новое письмо в базу данных, и после нажатия “Refresh” проверил бы, что оно появилось в инбоксе.

Новое письмо

Для составления нового письма нажимаем кнопку “COMPOSE”:

    $(byText("COMPOSE")).click();

И вбиваем адрес, тему и текст:

    $(By.name("to")).val("andrei.solntsev@gmail.com").pressTab();
    $(by("placeholder", "Subject")).val("ConfetQA demo!").pressTab();

    $(".editable").val("Hello braza!").pressEnter();
    $(byText("Send")).click();

В общем-то, совсем ничего сложного.

И в конце проверяем, что письмо отправилось:

    $(withText("Your message has been sent.")).shouldBe(visible);

Undo - redo

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

Итак, попробуем это протестировать. В конце предыдущего теста добавляем:

    $(byText("Undo")).click();
    highlight($(byText("Sending has been undone.")).should(appear));

Подправляем текст письма:

    $(".editable").should(appear).append("Hello from ConfetQA Selen").pressEnter().pressEnter();

    $(byText("Send")).click();

И ждём 10 секунд, пока кнопка “Undo” пропадёт:

    highlight($(withText("Your message has been sent.")).should(appear));
    highlight($(byText("Undo")).should(appear)).waitUntil(disappears, 12000);
    $(byText("Sent Mail")).click();

Письмо окончательно отослано адресату.

Вот теперь GMail протестирован, гугл может спать спокойно.

Выводы

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

  • Поиск элементов по тексту.
    Это максимально приближено к поведению пользователя и минимально зависит от реализации веб-приложения.
  • Тестировать только важное
    В приложении GMail ещё куча вещей осталась непротестированными. В данных условиях их, кажется, и невозможно протестировать (невозможность подсунуть тестовые данные, отсутствие статических локаторов). Но это не так уж и важно - главное, что критичные функции мы протестировали: показ писем в инбоксе и отсылка нового письма. Всегда начинайте с тестирования критичной функциональности, а остальное успеете оценить позже.
  • Используйте правильные инструменты
    Selenide автоматически решает проблемы с таймаутами, аяксом, динамическим контентом, поиском по тексту. Тесты не загрязнены длинными страшными XPath. Тесты содержат только логику. Тесты хорошо читаемые.


Простых вам тестов!

Андрей Солнцев
ru.selenide.org


The project is maintained by