Есть отличная удаленная работа для php+codeception+jenkins+allure+docker спецов. 100% remote! Присоединиться к проекту

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

interfaces
framework
page-object
webdriver
Теги: #<Tag:0x00007f7b65732958> #<Tag:0x00007f7b65732728> #<Tag:0x00007f7b65732480> #<Tag:0x00007f7b657322f0>

#1

Интересен опыт использования интерфейсов и абстрактных классов при создание фреймворка используя PageObject. По статьям которые мною были прочитаны многие используют обычные классы для описания страниц. Рекомендаций по использованию интерфейсов или абстрактных классов к сожалению я не нашёл.

Приветствуются примеры кода или ссылки на статьи про использование интерфейсов/абстрактных классов.


(Sergey Pirogov) #2

Не пишут потому что это оверхедно тулить интерфейсы и абстрактные классы для PO


(asolntsev) #3

Для начала определимя с тем, какую проблему мы решаем? Зачем нужны интерфейсы?


#4

Проблемы нет:slight_smile: Она мной выдумана. Интересна практика использования интерфейсов при разработке автотестов.


(Oleg Kuzovkov) #5

Я хотел что бы при наследовании страницы от базового класа (WebPage), компилятор мне говорил что должен быть реализован метод invoke_actions() и прописано поле web_page_id (идентификатор страницы), а в методе invoke() WebPage класа, у меня выполнялась стандартная проверна на exists() страницы перед вызовом invoke_actions() страницы.

Конечно же добиться желаемого получилось только при использовании абстрактного класа WebPage. Так же в в этом класе и реализован метод exists(), который использует web_page_id для проверки существования страницы.

class WebPage:
metaclass = ABCMeta

@abstractmethod
def invoke_actions(self):
    pass
def invoke(self):
    if not self.exists():
        Log.info("Invoking %s web page" % Log.get_caller_class_name())
        self.invoke_actions()
        assert self.exists(10)
@property
def web_page_id(self):
    raise NotImplementedError
def exists(self, time=0):
    Log.info("Page '%s' existence verification. Wait time = %s" % (Log.get_caller_class_name(), str(time)))
    try:
        WebDriverWait(Browser().driver, time).until(
            EC.visibility_of_element_located(self.web_page_id)
        )
        return True
    except (NoSuchElementException, TimeoutException) as e:
        return False

Так же мне не нужно было что бы кто то мог создать обьект класа WebPage, это еще одна причина использования Abstract classа.


(Eugene Moskalenko) #6

Хм… Java 8 дает возможность обойти наследование от одного класса, с помощью интерфейсов с дефолтной реализацией… :slight_smile: Возможно это противоречит ООП, но для автоматизатора может существенно пригодиться и решить кое какие задачи :slight_smile:

Почти полноценное множественное наследование…

Такие интерфейсы не хранят состояние, но могут иметь какое-то дефолтное поведение.

public interface Validator {

    @Step("Verify that \"{1}\" = \"{0}\"")
    default void verifyTextEquals(final String actual, final String expected, final String message) {
        assertEquals(actual, expected, message);
    }

    @Step("Verify that \"{1}\" = \"{0}\"")
    default void verifyTextEquals(final String actual, final String expected) {
        assertEquals(actual, expected);
    }

    @Step("Verify that \"{0}\" contains \"{1}\"")
    default void verifyTextContains(final String actual, final String containsString) {
        assertTrue(actual.contains(containsString));
    }

    @Step("Verify that \"{0}\" not contains \"{1}\"")
    default void verifyTextNotContains(final String actual, final String containsString) {
        assertTrue(!actual.contains(containsString));
    }
    
}

в тесте можно использовать так:

public class Login extends BaseTest implements Validator {

    @Title("Main logIn form")
    @Test(enabled = true, groups = "Login", priority = 10)
    public void signIn() {
        //------------------- Test Data -------------------//
        String name = "qa-login";
        String pass = "qa-pass";

        // --------------------- Test Case ----------------------//
        PopUp popUp = loginPage().open("/login.html").loginWith(name, pass);
        verifyTextEquals(popUp.getTitleMessages(), "111!");
    }
}

Я вот кстати не совсем уверен, можно ли такое применять, но работкает и решает некие проблемки :slight_smile:

А классический интерфейс, где идет описание и класс с реализацией, мне так и не удалось придумать куда бы применить, и не было еще такой задачи, чтобы интерфейсы решили какую-то проблему…

А вот абстрактные классы, напротив - могут хранить состояние и в них можно скинуть кучу каких-то методов, которые могут использоваться в дочерних классах… Или же объявить там абстрактные методы…

public abstract class BaseScreen<T extends BaseScreen<T>> {

    private static final Logger logger = LogManager.getLogger(BaseScreen.class);

    public abstract T chooseContact(SocialAppSection socialAppSection);

    public abstract T sendTextMessages(SocialAppSection socialAppSection);

    public abstract T sendLikeButtonInMessage();

    public abstract T sendPhotoInMessage();

    public abstract T sendVideoInMessage(int longPressTime);

    public abstract T sendAttachInMessage();
}

(Рома Иовлев) #7

Можете посмотттреть на фреймворк JDI. https://github.com/epam/JDI
Он построен на основании интерфесов. Основная мысль, что с точки зрения человека элемнты на странице умеют делать одно и тоже вне зависимости от ее разметки или даже типа приложения (веб это или мобильные или десктоп) Дропдаун - это дропдаун, кнопка - это кнопка, таблица - это таблица - с понятными действиями
Примеры можно посмотреть, тут https://github.com/epam/JDI/blob/master/Java/Tests/jdi-uitest-tutorialtests/src/main/java/com/epam/jdi/uitests/testing/career/page_objects/site/sections/AddCVForm.java

Настроенный пустой проект можно скачать тут: https://github.com/epam/JDI-Examples/archive/master.zip

Презентации и другая информация в группе вконтакте: https://vk.com/jdi_framework
и на сайте: http://jdi.epam.com/

Будут вопросы, обращайтесь )))


(Vladimir Gerastovskiy) #8

Открыл для себя недавно ваш фреймворк - очень понравилась идея и реализация.
Не собираетесь внедрять что-то подобное для API тестирования? Например, JSON/XML RESTful API


(Рома Иовлев) #9

Да, думаем. Уже есть наработки внутри компании, но пока не готовы поделится )


(inkvizitorz) #10

Доброго времени суток!

А каким образом можно настроить JDI для использования совместно с JUnit?


(Oleksandr Khotemskyi) #11

Не очень понимаю как идея фрагментов подходит под API тесты.

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


(Oleksandr Khotemskyi) #12

Вот бы ща в некротред попостить…