Интересные исходники кода автоматизации разных проектов или фреймворков

GitHub, BitBucket и другие системы храненния публичного кода содержат множество примеров интересных реализаций автоматизации

Кто-то их находит, а кто-то не может. Давайте делиться ссылками и описаниями, кто что нашел

3 лайка

Вот Дима Жарий недавно показал ссылку на реализацию C# фреймворка на webdriver https://github.com/athrunsun/csharp-automaton

там и PageObject и утилиты и кейворды

в общем, интересно посмотреть

действительно интересно, хоть и C#.

добавил в закладки :)

делюсь своим кодом, недавно делал модуль для Robot Framework на python, который работает с вебсервисами

пример кода можно посмотреть тут https://github.com/polusok/RF-WebServicesLibrary

1 лайк

Intuitive, robust browser automation for .Net

позволяет писать код в виде

// Drop downs

browser.Select("toyota").From("make");

// Text inputs
browser.FillIn("keywords").With("hybrid");

// File inputs
browser.FillIn("Avatar").With(@"c:\users\adiel\photos\avatar.jpg");

// Radio button lists
browser.Choose("Trade");
browser.Choose("Private");

// Checkboxes
browser.Check("Additional ads")
browser.Uncheck("Additional ads") 

а на java есть что то стоящее?

Thucydides is a java tool that lets you use WebDriver-based unit or
BDD tests to write more flexible and more reusable WebDriver-based
tests, and also to generate documentation about your acceptance tests,
including a narrative description of test, along with the
corresponding screen shots, and also high-level summaries and
aggregations of the test results

Тесты выглядят где-то так

package net.thucydides.demo;
 
import net.thucydides.core.annotations.Managed;
import net.thucydides.core.annotations.ManagedPages;
import net.thucydides.core.annotations.Steps;
import net.thucydides.core.pages.Pages;
import net.thucydides.demo.steps.GoogleSearchSteps;
import net.thucydides.junit.runners.ThucydidesRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
 
@RunWith(ThucydidesRunner.class)
public class SearchingOnGoogleStory {
 
    @Managed
    public WebDriver webdriver;
 
    @ManagedPages(defaultUrl = "http://www.google.com")
    public Pages pages;
    
    @Steps
    public GoogleSearchSteps steps;
 
    @Test
    public void searching_for_cats_should_find_the_wikipedia_entry() {
        steps.open_home_page();
        steps.searchFor("cats");
        steps.resultListShouldContain("Cat - Wikipedia, the free encyclopedia");
   }
    
    @Test
    public void searching_for_dogs_should_find_the_wikipedia_entry() {
        steps.open_home_page();
        steps.searchFor("dogs");
        steps.resultListShouldContain("Dog - Wikipedia, the free encyclopedia");
    }
    
    @Test
    public void searching_for_hamsters_should_find_the_wikipedia_entry() {
        steps.open_home_page();
        steps.searchFor("hamsters");
        steps.resultListShouldContain("Hamster - Wikipedia, the free encyclopedia");
    }
}
1 лайк

Selenide is a library for easier using of Selenium WebDriver for
automated tests in Java.

Код, где-то выглядит так

@Test
public void testLogin() {
  open("/login");
  setValue(By.name("user.name"), "johny");
  followLink(By.id("submit"));
  waitUntil(By.id("username"), hasText("Hello, Johny!"));

  assertThat($("#insuranceDetailsHeader").getText(), equalTo("Страховые полисы"));
  assertThat($$("#paymentScheduleTable tr").size(), equalTo(7));
}
1 лайк

Смотрел я на Thucydides. В целом, впечатления неоднозначные. Как по мне, они пытаются изобрести нечто универсальное, на все случаи жизни. Фреймворк еще очень сырой. До предпоследней версии не было поддержки масштабируемости, до сих пор не прикрутили testng. Плюс ко всему, там такая гора кода, что на его изучение, когда придется что-то прикручивать (а придется 100%), уйдет немало времени и сил. Доки пока тоже не очень впечатлили.

Эта штука еще тоже достаточно сырая, но она мне понравилась больше, чем предыдущий вариант, ибо не содержит ничего лишнего. Кода немного, написан доступно и понятно. Прикрутить что-либо не составит особо труда. С доками - пока беда. Единственный минус по сравнению с Thucydides - придется писать еще один уровень обертки для тестовой логики, т.к. в текущем виде оно будет не очень читабельным.

Почему то захотелось сказать - "хочешь использовать что-то хорошее - сделай это сам".  :)

А так - да, интересные либы, спасибо. 

это конечно да, но если есть время, желание и знания

Здравствуйте,

действительно, основные преимущества Selenide - это простота и минимализм.

За последнее время мы добавили доков и API заметно подрос. Теперь можно писать так:

@Test
public void userCanLoginByUsername() {
  open("/login");
  $(By.name("user.name")).setValue("johny");
  $("#submit").click();

  $(".loading_progress").should(disappear); // Waits until element disappears
  $("#username").shouldHave(text("Hello, Johny!")); // Waits until element gets text
}

А не могли бы вы рассказать подробнее, что ещё за уровень обёртки придётся дописывать?

1 лайк

Добрый день, 

Если честно, уже не помню, что именно меня тогда смутило. Нужно опять смотреть исходники. Но скажу на примере последних 3х проектов: заказчики просили создавать такой уровень абстракции, чтобы тесты могли писать люди без особых знаний программирования. Обращения по типу $(locator).method() в такой ситуации будут слишком сложными для восприятия. Даже при условии вынесения этого кода на уровень PageObjects. Внедрение дополнительного уровня абстрации может отразиться и на самих локаторах (опять-таки для улучшения читабельности и кастомных решений). Поддерживает ли ваш фреймворк на текущий момент возможность обработки кастомных локаторов? Смогу ли я переопределить существующие обработчики?

Из того, что запомнилось, есть несколько пожеланий: 1) хотелось бы видеть во фреймворке не статический драйвер; 2) было бы неплохо реализовать SoftAsserts механизм; 3) не помешал бы какой-то интерфейс, который позволит мне самому выбирать, когда убивать драйвер. По-моему, на тот момент убиение драйвера было заключено под JUnit'овский @After. Что если я использую testng и хочу создавать / убивать драйвер после каждого метода? 4) если не ошибаюсь, метод для снятия скринов был заточен сугубо под обычный WebDriver, для RemoteWebDriver нужно дополнительное преобразование с использованием Augmenter.

Возможно все это уже добавлено / исправлено в последних версиях. Повторюсь, давно не смотрел код. Но в целом, впечатления остались неплохие.

Спасибо за много интересных вопросов.

Давайте по порядку.

1. Да, можно делать сколько угодно уровней абстракций. Фокус в том, что Selenide не накладывает никаких ограничений: можно сделать и PageObject, и StepObject, и наворотить ещё каких угодно слоёв, а можно обойтись и без них - как душа пожелает. Я лично склоняюсь к тому, что уровни, которые вас заставляет создавать, например, Thucidides, скорее искуственные, и они больше мешают, чем помогают. Но если действительно надо, то технически ничто не мешает.

2. Не уверен, что такое кастомные локаторы, но думаю, что поддерживает. Никто же не мешает переопределить класс By. Это справедливо и для простого Selenium.

3. Не знаю, что такое "существующие обработчики" и что означает их "переопределить", но мы старались делать Selenide по такой идеологии, что переопределить можно всё.

 

По пожеланиям:

1. Что такое "нестатический" драйвер? А какой тогда? Сейчас есть возможность сказать Selenide использовать ваш объект WebDriver - это оно?

WebDriverRunner.setWebDriver(myDriver)

2. SoftAsserts - это когда тест не падает, а продолжает идти дальше, и только в конце показывает ошибку? Убеждён, что это в принципе неправильно. Если это кому-то понадобилось, то проблема глубже, и решать её надо другими методами.

3. Есть такой метод для JUnit: https://github.com/codeborne/selenide/blob/master/src/main/java/com/codeborne/selenide/junit/BrowserStrategy.java

Но теперь я стал думать, что он не нужен. Ведь вы можете всегда написать свой метод @After, в котором вызвать WebDriverRunner.close()

4. Да, снятие скриншотов реализовано только для обычного WebDriver. Я просто никогда не использовал RemoteWebDriver  и не знал, что там скриншоты надо делать как-то по-другому. Скиньте пример, сделаем по-быстрому. 

 

 

  1. Нестатический драйвер - тот, у которого отсутствует модификатор static. И не важно при этом, каким я его создам. Главное то, что после вызова:
public static void setWebDriver(WebDriver webDriver) {
    webdriver = webDriver;
}

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

  1. SoftAsserts.

В некоторых компаниях, работающих над серьезными проектами (по типу медицинских - с жесткой формализацией) существует такая техника написания тест кейсов, в которой все степы делятся на инстракшенал и верифай. При этом, каждый верифай степ проверяет функционал на соответствие задокументированному требованию. Так вот представьте тест кейс из 200+ степов, в котором 70% из них - верифай степы. Разбивать 1 тест кейс на 140 (по 1 верифаю в каждом) является нецелесообразным, уже не говоря о тонне ненужных прекондишенов в случае фейла предыдущего теста.

К тому же, механизм SoftAssert не так давно встроили в TestNG. Значит спрос на подобный функционал таки имеется среди автоматизаторов всего мира.

  1. Screen capture for RWD:
File scrFile;
 
if (driver.getClass().equals(RemoteWebDriver.class)) {
    scrFile = ((TakesScreenshot) new Augmenter().augment(driver)).getScreenshotAs(OutputType.FILE);
} else {
    scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
}

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

Но достичь её можно гораздо проще. Можно же запустить в одном процессе "ant -Dbrowser=firefox", в другом "ant -Dbrowser=chrome" и в третьем "ant -Dbrowser=ie".

Та же самая масштабируемость достигнута? Достигнута. Легко? Легко. Нужно ли что-то ещё изобретать?

Подскажите! Если окажется, что нужно, сделаем в два счёта.

2. Разбивать кейс на 400, конечно, не надо. Пусть будет в одном тесте 400 проверок. Но ведь если хотя бы одна из них упадёт, то и весь тест должен упасть, верно? И зачем тогда гнать его до конца и делать остальные 399 проверок? Только время тратить. Пусть уж он побыстрее упадёт и мы побыстрее его исправим.

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

Но тут у меня встаёт техническая трудность: такую штуку можно реализовать только под какие-то конкретные фреймворки. Понимаете, сам по себе Selenide универсален, его можно использовать и с JUnit, и с TestNG, и с ScalaTest, и с Groovy и с чем угодно. Мы можем сделать SoftAssert, скажем, для JUnit и TestNG, но остальные фреймворки останутся непокрытыми.

Пожалуй, можно сделать. Я создал таск на гитхабе. Спасибо за предложение.

3. Спасибо, создал таск. Хотя мне до сих пор непонятно, нафига нужен RemoteWebDriver. По той же причине, что п. 1.

 

1) А если мне нужно стартануть 30 конфигураций (различные версии ОС / браузеров)? Запускать 30 таргетов как независимые процессы в параллельном режиме?

От статики можно избавиться путем наследования тестом WebDriverRunner и иницилизации драйвера в каком-нибудь из аннотированных @Before методе. При этом, убиение драйвера будет под одной из аннотаций @After.

Кстати, у вас в методе closeWebDriver лучше использовать driver.quit() вместо driver.close(), т.к. close() лишь закрывает браузер, а quit(), помимо браузера, убивает и сам драйвер. Это легко отследить в таск менеджере: при запуске ie или chrome, вызов метода close() оставит висеть драйвер в процессах по завершению теста.

2) В том то и дело, что в случае 400 проверок общий экзекьюшен тайм будет слишком долгий, и проще сразу увидеть все фейлы, нежели запускать тест после каждого индивидуального фикса.

Полной универсальности порой чисто физически невозможно достигнуть в силу каких-либо ограничений.

3) RemoteWebDriver изначально затачивался под грид. Возможно для вас и проще поднять Jenkins c кучей агентов, но... Во-первых, у CI несколько иное предназначение и использовать его целесообразно только по назначению / в комплексе, а не сугубо ради одной фичи. Во-вторых, Jenkins настроить далеко не проще, нежели запустить простой батник. Ну и последнее, есть компании / проекты, на которых дополнительная тулзовина должна пройти серьезную валидацию, прежде чем ее допустят к использованию (даже не смотря на фришность), посему заказчики выбирают вариант наименьшего сопротивления, т.е. one-click solution, аля запуска через cmd без установки каких-либо дополнительных тулов.

 

1. Конечно, это же явно проще!
Если на то пошло, никто ведь не собирается это делать на своём компьютере? Эти 30 конфигураций вы ведь собираетесь запускать на Jenins?
Ну вот и создайте в нём 30 тасков, каждый запускает полный комплект тестов со своей конфигурацией. 
 
Может, я чего не понимаю, но по-моему, это явно проще и логичнее, чем что-то подобное имплементировать внутри тестов. 
 
У CI как раз такое предназначение и есть: делать кучу однообразной работы с разными конфигурациями, на разных опсистемах и т.д. Jenkins c кучей агентов - это очень даже по назначению.
 
(Насчёт close vs quite посмотрю, спасибо за подсказку.)
 
3. Хм.. но ведь грид - это тоже тулзовина, не? Её ведь тоже нужно поднять? 
Читаем описание Грид: Selenium Grid распределяет запуск ваших тестов на многих машинах. Значит, его тоже нужно установить на всех этих машинах. Как же возможно это поднять одним батником?..

1) При условии нестатического драйвера у меня будет единственный процесс + 1 xml с нужной конфигурацией. Внутри тестов ничего меняться не будет, кроме собственно самого наследования ранэра. И в Jenkins нужно будет создать всего 1 джобу, а не 30.

3) Грид - сложно назвать тулзовиной. Мы просто запускаем все тот же selenium-standalone джар с доп. параметрами в батнике. В зависимости от параметров, эти батники будут величаться хабами / нодами. Но в душе - это одна и та же либа. Технически, ничего кроме джавы, ставить не нужно. Лишь переписать и запустить батники с джаркой.