Не могу сложить пазлы (webdriver + pytest + webium)

Здравствуйте, создаю инструмент, на основе webdriver + pytest.
Смотрел уроки @polusok и читал его статьи - огромное спасибо Вам!)

Так же просмотрел видео про webium и решил его заюзать.

Я пока не могу сложить общую картину у себя в голове.
Значит, что я делаю:

Я разбил проект на три сущности:
/page_objects
/test_case
/common

Вот пример одного из класса PageObject

page_objects.login_page.py

from selenium.webdriver.common.by import By
from main_page import MainPage
from webium import BasePage, Find

class LoginPage(BasePage):

    _login_loc = Find(by=By.XPATH, value="//input[@id='login']")
    _password_loc = Find(by=By.XPATH, value="//input[@id='password']")
    _submit_loc = Find(by=By.XPATH, value="//input[@value = 'ВОЙТИ']")

    def __init__(self, driver):
        BasePage.__init__(self, driver, url="http://eb-core-test-sso.otr.ru:7777/udu-webcenter")

    # Actions

    def type_login(self, str_login):
        self._login_loc.send_keys(str_login)

    def type_password(self, str_password):
        self._password_loc.send_keys(str_password)

    def submit_login(self):
        self._submit_loc.submit()
        return MainPage(self._driver)

    def login_ass(self, str_login, str_password):
        self.type_login(str_login)
        self.type_password(str_password)
        return self.submit_login()

Затем в test_case я хочу написать тест

test_case.test_login.py

 import pytest
 from common.base_test import BaseTest
 from page_objects.login_page import LoginPage
    
    
 class TestLogin(BaseTest):
   

 def __init__(self):
        self.login_page = LoginPage()

    _str_login = "000_Sistema.RS"
    _str_password = "Bvthn4kxGc"

    def test_login(self, driver):
        main_page = self.login_ass(self._str_login, self._str_password)
        assert u"Главное меню" in main_page.get_title()


if __name__ == "__main__":
    pytest.main()

вот тут я не понимаю уже как мне его сделать грамотно… Мне надо как-то создать объект webdriver и передать его в LoginPage()…
в голове все перепуталось

Я хотел, чтобы инстанс веб-драйвера передавался из тест-кейса в тест-кейс и я увидел такой рецепт от @polusok

common.conftest.py

import pytest
from selenium import webdriver

class DriverManager(object):

    def __init__(self):
        self._instance = None

    def start(self, type="ff"):
        self._instance = webdriver.Firefox()
        return self._instance

    @property
    def instatnce(self):
        if not self._instance:
            self.start()
        return self._instance

    def stop(self):
        self._instance.close()


@pytest.fixture(scope="module")
def driver():
    return DriverManager()

common.base_test.py

import pytest


class BaseTest(object):

    @pytest.fixture(scope="class")
    def manager_driver(self, request, driver):
        driver.start()
        request.addfinalizer(driver.stop)

Коллеги, прошу помочь…
Может ссылками полезными, статьями, а может советами конкретными.
Я не понимаю как состыковать свои классы page_object с test_case.

Спокойствие, никто не знает)

Я вчера нашел весьма занимательный проект, так в полной мере описывается как писать тесты webdriver+selenium

вот: Google Code Archive - Long-term storage for Google Code Project Hosting.

Рекомендую выкачать весь проект и пройтись по нем

1 лайк

спасибо) сейчас гляну)

По webium @Igor поможет, когда прочитает :smile: да и наверное покажет как у них передается webdriver instance.

А вообще, фикстуру (которую вы указали) я делал для другого случая. Если у вас нет таких требований, как были там ( Глобальная фикструра с передачей данных в pytest ) то нет смысла привязывать этот код. Вам в данном случае не нужно пробрасывать инстанс вебдрайвера каждый раз в каждый page object, это накладно. Можно просто отделить инициализацию вебдрайвера и вызывать там где его нужно. На пример (примерочный код не означает что его ненужно дорабатывать до ваших потребностей, ведь я не умею читать ваши мысли):

common.py

from selenium import webdriver


class Driver(object):
    __instance = None

    @classmethod
    def get(cls, type='ff'):
        # write driver instance init logic here depending on argument
        if not cls.__instance:
            cls.__instance = webdriver.Firefox()
        return cls.__instance


class BaseTest(object):
    def teardown_class(self):
        Driver.get().close()

page_objects.py

from selenium.webdriver.common.by import By
from webium import BasePage, Find
from common import Driver


class AbstractBasePage(BasePage):

    def __init__(self, url):
        BasePage.__init__(self, Driver.get(), url)

    def get_title(self):
        return Driver.get().title


class DashboardPage(AbstractBasePage):

    _first_lesson = Find(
        by=By.XPATH, value="(//div[contains(@class, 'lesson-block')])[1]/a")

    def __init__(self):
        AbstractBasePage.__init__(self, "http://lessons2.ru")

    def open_first_lesson(self):
        self._first_lesson.click()
        return LessonPage()


class LessonPage(AbstractBasePage):
    _name = Find(by=By.CSS_SELECTOR, value="h1")

    def __init__(self):
        AbstractBasePage.__init__(
            self, "http://lessons2.ru/lesson/preview/issleduem-vozmozhnosti-robotframework/")

    def get_lesson_name(self):
        return self._name.text

test_lessons2ru.py

# -*- coding: utf-8 -*-
import pytest
from page_objects import DashboardPage
from common import BaseTest


class TestLogin(BaseTest):

    def test_lesson_1(self):
        main_page = DashboardPage()
        main_page.open()
        assert u"Lessons2.ru" in main_page.get_title()
        lesson = main_page.open_first_lesson()
        expected_name = u'Исследуем возможности Robot Framework'
        assert expected_name in lesson.get_lesson_name()

    def test_lesson_2(self):
        main_page = DashboardPage()
        main_page.open()
        assert u"Lessons2.ru" in main_page.get_title()
        lesson = main_page.open_first_lesson()
        expected_name = u'Использование модулей и пакетов в Python'
        assert expected_name in lesson.get_lesson_name()


if __name__ == "__main__":
    pytest.main()

Получаю ожидаемый результат, страницы работают, инстанс передается без проблем:

============================= test session starts =============================
platform win32 -- Python 2.7.3 -- py-1.4.26 -- pytest-2.7.0
rootdir: D:\temp\demo\pytest+webium, inifile: 
plugins: xdist
collected 2 items

test_lessons2ru.py .F

================================== FAILURES ===================================
___________________________ TestLogin.test_lesson_2 ___________________________

self = <test_lessons2ru.TestLogin object at 0x0326F610>

    def test_lesson_2(self):
        main_page = DashboardPage()
        main_page.open()
        assert u"Lessons2.ru" in main_page.get_title()
        lesson = main_page.open_first_lesson()
        expected_name = u'Использование модулей и пакетов в Python'
>       assert expected_name in lesson.get_lesson_name()
E       assert 'Использование модулей и пакетов в Python' in 'Урок: Исследуем возможности Robot Framework Robot Framework'
E        +  where 'Урок: Исследуем возможности Robot Framework Robot Framework' = <bound method LessonPage.get_lesson_name of <page_objects.LessonPage object at 0x0326F5F0>>()
E        +    where <bound method LessonPage.get_lesson_name of <page_objects.LessonPage object at 0x0326F5F0>> = <page_objects.LessonPage object at 0x0326F5F0>.get_lesson_name

test_lessons2ru.py:23: AssertionError
===================== 1 failed, 1 passed in 11.84 seconds =====================

***Repl Closed***

Весь код выложил в тут https://gist.github.com/polusok/3122a7f6575111965906

1 лайк

Спасибо! Буду копать!)
Кстати, видео про webium - было выступление @Igor
=)

Ну чего же не знает, знаю и даже прокоментировал :smile:

Да, в обучающих целях полезно на код посмотреть. Даже видел что-то похожее на github вот ссылка GitHub - ir-il/python_training_for_testers, но весь этот код простой так что разобраться сможете. А если будут ньюансы, пишите.

Копайте. Да @Igor принимал участие в разработке webium. Ну и как найдете решение обязательно ждем его здесь в полной форме для других, иначе тогда не интересно вообще помогать. Ну и не пользоваться лайками :smile:

1 лайк

ок =)

может сначала попробовать заюзать unittest?
он вроде как понятней)

Я не знаю что Вы делаете и каких целей хотите достичь, потому порекомендовать ничего не могу. Автоматизацию тестирования можно в равной степени реализовать и с помощью unittest, и с pytest и с nosetests. Все зависит от того что Вы строите.

Ну и если для unittest более понятный, так начните с него, а дальше будет видно. Если все устраивает, то используйте. Если что-то не будет, тогда и ищите как решить конкретные проблемы. А так сейчас бьетесь об стену непонимания, а надо начинать с малого (что работает) и двигаться к большему (к оптимизации и эффективности).

1 лайк

Спасибо!

Я образно сказал, так как сам был в такой ситуации)

from webium.driver import close_driver

class BaseTest(object):
    def teardown_class(self):
        close_driver()

По большому счёту этого будет достаточно для минимальной интеграции py.test и webium. В PageObject’ы даже не надо будет инстанс передавать.

webium.settings.driver_class - сюда можете установить другой драйвер.

В коробке webium идёт интеграция с nose через плагин.

Буду рад видеть Pull Request на встроенную интеграцию с py.test.

3 лайка

понравилось название метода :slight_smile:

    def login_ass(self, str_login, str_password)
2 лайка

ага)) это я тупанул)

а где можно почитать про это?)

@Viktor_Borisov, по поводу почитать… Даже не знаю, о чём сильно писать-то.

webium/browser_closer.py at master · wgnet/webium · GitHub - тут код. Плагин простой, написан согласно этой документации: Writing Plugins — nose 1.3.7 documentation.

2 лайка

Судя по коду в common.py, данный набор не будет работать, если добавить еще один тестовый класс, в этом случае при закрытии первого класса выполнится команда
def teardown_class(self):
Driver.get().close()
и браузер будет закрыт, но инстанс останется и будет ошибка.
Тут не подразумевается добавление второго тестового класса, или я не совсем правильно понял код?

Блин, никогда в жизни не используйте этот webium я из-за него собеседование провалил. Готовые библиотеки паттерна pageobject кто-то создавал для своих личных целей, а затем просто решил расшарить, как это сделал warthunder. Он просто может и не подойди вам. Если вы хотите реально научиться в автоматизации, то учите selenium пока не сможете создать свой нормальный паттеррн. Все необходимое в selenium есть. Берете selenium + pytest или selenium + nosetests и все.