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

Зависимость тестов и порядок их выполнения в python тестах

page-object
unittest
execution
python
webdriver
Теги: #<Tag:0x00007f7b6d135160> #<Tag:0x00007f7b6d134e68> #<Tag:0x00007f7b6d134cb0> #<Tag:0x00007f7b6d134a80> #<Tag:0x00007f7b6d134828>

(Дмитрий Золкин) #1

Не так давно пишу на Python + Webdriver +unittest.
Проблема в следующем.Везде написано, что писать зависимые друг от друга тесты плохо.
У меня на данном этапе есть проект, в корне которого куча файлов py.
Пытаюсь использовать PageObject подход.
Есть файл locators.py , в котором хранятся просто локаторы в виде FIELD_RECIVER =(By.CLASSNAME, "reciver")
Есть файл page.py, в котором хранится мой класс страницы с методами пример кода:

class BasePage(object):
    ``def __init__(self, driver):
        self.driver = driver

class MainPage(BasePage):

    def fill_field(self, locatror, text):
        try:
            WebDriverWait(self.driver, 10).until(
                EC.presence_of_element_located(locator)
            ).send_keys(text)
        except TimeoutException:
            raise Exception("Время появления поля ввода истекло.Не удалось ввести значение в поле ввода")

Есть собственно файл tests.py, в котором сами тесты в виде:

driver = None
def setUpModule():
    global driver
    driver = webdriver.Firefox()
    driver.get("http://root:11111111@172.23.78.61")


class Reference_19_10_section_1_1_3(unittest.TestCase):
## Первый тест
    def test_1_open_form(self):
        main_page = page.MainPage(driver)
        main_page.click_button(*Locators_19_10.REFERENCE_LINK)
        time.sleep(1)
        main_page.click_to_type_ref(*Locators_19_10.REFERENCE_19_10)
        main_page.click_button(*Locators_19_10.BUTTON_CREATE_REFERENCE)
        assert "Строка" in main_page.find_title_in_element(
            *Locators_19_10.REFERENCE_TITLE_TEXT)
##Второй тест
    def test_3_fill_reference_reciver(self):
        main_page = page.MainPage(driver)
        main_page.fill_field(locators_list_body_19_10[1], required_dict_for_body_19_10['reciver'])
        assert u'Тестовый документ принял' in main_page.find_text_in_element(*Locators_19_10.REFERENCE_RECIVER)

То есть я получаю, что если не пройдет первый тест, то и второй тоже не пройдет потому, что он не увидит локатора.
Тест делает следующее: нажимает кнопку, появляется форма проверяется, что заголовок формы соответствует. Во втором тесте, заполняется поле "Получатель "в форме, которая появилась и проверка того, что в поле ввелось значение…

Как можно сделать их независимыми??Может я разбил на слишком маленькие тест кейсы и стоит заполнять полностью форму и потом, что-то проверять.В самой форме еще много кнопок, которые вызывают другие формы. И я стараюсь писать тест на каждое заполнение поля или каждый выбор из списка.

И еще маленький вопрос, как можно управлять порядком выполнения теста.? В unittest все выполняется по алфавиту. На данном этапе я пишу
def test_1
def test_9
def test__10 и тд.
и если падает какой-то из скажем так глобальных тестов, которые вызывает новую форму, то все тесты которые что то заполняют в ней тоже падают…


(Oleg Kuzovkov) #2

Ух товарищ, я буквально 2 недели назад решил эту задачку.

Что посоветую - перейдите на pytest вместо unittest и используйте фикстуры. С их помощью мне удалось сделать мои тесты независимые.

Ссылки:
http://devork.be/talks/advanced-fixtures/advfix.html
http://programeveryday.com/post/pytest-creating-and-using-fixtures-for-streamlined-testing/


(Дмитрий Золкин) #3

Спасибо за ответ. Буду пробовать


(Oleksandr Khotemskyi) #4

Как по мне разбито слишком мелко. Зависимые вот так как у тебя тесты - плохо - а вдруг в первом тесте что-то не так пройдет? В моих текущих тестах я например вообще чищу весь браузер перед каждым тестом чтобы небыло зависимости даже случайной


(Oleksandr Khotemskyi) #5

а как фикстуры помогут при тестах в браузере? Приведи пример кода если можешь.


(Oleg Kuzovkov) #6

Вот 3 теста, котрые требуют создания нового пользователя.
Логика создания вынесена в фикстуру, а тестовый класс требует выполнение этой фикстуры. Если фикстура сломаеться - все 3 теста будут фейл. Но каждый из тестов абсолютно независим, и может быть стартанут безо всяких проблем индивидуально.
Судя по Вашей логике, мне нада было создавать нового пользователя для каждого из тестов, но зачем, если можно использовать уже созданного пользователя с первого/второго/третего теста? Не так ли?

@pytest.mark.usefixtures("create_retailer")
class TestSetup:
    
    def test_create_new_retailer(self):
        assert get_retailer_id() is not None, 'Unable to find created retailer in the Retailers table'

    def test_book_appointment(self):
        try:
            page = BookYourSessionPage()
            page.invoke()
            page.schedule_personal_session()
            wait_time=JSONReader.get_data_from_config_json("global_configuration","default_iframe_load_time")
            assert page.confirmed.exists(wait_time), "Unable to find 'Confirmed' window after '%s' seconds" % str(wait_time)
        finally:
            Browser().refresh()

    def test_check_if_top_nav_lauch_program_link_exists_and_displayed(self):
        Browser().open(JSONReader.get_data_from_config_json("qa_environment_links","url"))
        top_nav=GeneralTopNav()
        top_nav.invoke()
        assert top_nav.lauch_program.is_displayed(), 'Launch Program logo is not exists'

(ex3me0) #7

Приведите пример фикстуры? Иначе - этот пример бесполезен. Спасибо.

И да…

from JSONReader import get_data_from_config_json as get_data

а то что-то у Вас больше на джаву похоже


(ex3me0) #8

По сути топика: так же советую перейти на py.test (делается это совсем безболезненно, обратная поддержка юниттеста2 там предусмотрена), и заюзать плагин к нему http://pytest-ordering.readthedocs.io/en/develop/


(Oleg Kuzovkov) #9

Приведите пример фикстуры? Иначе - этот пример бесполезен. Спасибо.

Как бесполезен? 0_0 Думал главное идею подать. Но раз Вам все расставит на свои места сама фикстура, пожалуйста:

@pytest.fixture(scope="session", autouse=True)
def create_retailer(request):
    sign_up_page = SignUpPage()
    sign_up_page.invoke()
    sign_up_page.create_new_retailer(retailer_first_name, retailer_last_name, retailer_email, retailer_password)

    def finalizer():
        Browser().quit()
    request.addfinalizer(finalizer)

from JSONReader import get_data_from_config_json as get_data

Спасибо за совет. С джавы месяц как спрыгнул, привычка еще осталась :slight_smile:


(Bolatbek) #10

Главное, все спрыгивают, и все довольны питоном.
Но на джаву вакансий больше (


(Sergey Korol) #11

Мне вот интересно кто это - все? :slight_smile: Но главный вопрос даже в другом - по какой причине?


(Bolatbek) #12

Ну по этому форуму - знаю двоих ).
Плюс - среди знакомых автоматизаторов в реальной не форумной жизни - несколько человек.
Причина - банально быстрее и понятнее.

Из соседней темы:


(Sergey Korol) #13

Ну я бы не стал обобщать несколько человек до масштаба всех. :slight_smile:
И на результаты приведенного опроса я бы тоже не сильно ориентировался, т.к. выборка ограничивается сэмплами весьма ограниченного числа компаний / девелоперов. Кто они все? Страны? Сферы деятельности? Без дополнительной информации этот опрос не представляет абсолютно никакой ценности.

А скорость (кстати чего?) и понятность - уж очень относительные явления. К примеру, рассматривая типы данных, как же строго типизированный язык может оказаться менее понятным? Тут как раз-таки все весьма очевидно. Ну а если человеку лень читать, то даже супер-простые языки у него будут вызывать немалые сложности в освоении.


(Oleg Kuzovkov) #14

Гибкость, скорость, простота. Делаешь почти что хочешь и где хочешь. Джава в этом плане очень строгий язык.
Это то что я могу сказать спустя месяц работы.

Причина “спрыгивания”, так сказали на новом месте, против моей воли. Если бы не сказали - остался бы на джаве. Доволен тем что получил возможность освоить новый язык :slight_smile:


(Bolatbek) #15

Ну вы тоже правы.
Спорить не буду. Пусть так и будет.


(Дмитрий Золкин) #16

С фикстурами пока тяжко потому, что не особо въехал в декараторы… По мере работы читаю Лутца,но времени не особо… Как я понял ,фиксутра приводит в какое-то состояние систему.Но я не понимаю, как мне обойти порядок и повтор кода(((
У меня форма, в ней заполнить надо обязательные поля(если не заполнить при сохранении ничего не сохранится т.к не заполнены поля.
Проблема такая, что после вызова первой формы вызывается вторая , во второй список в зависимости от выбора из списка при нажатии кнопки появляется различная третья форма, после ее заполнения данные заносятся во вторую форму из второй в первую и только после такой процедуры при нажатии на “Сохранить” данные заносятся в базу(ну или для меня появляются в списке т.к в базу я пока не лезу)
На данном этапе мне пришлось тупо копировать первые 10 тестов(тесты мелкие) из 1 модуля, что б дойти до списка с выбором от, которого зависит третья форма. Мне что в фикстуру надо вынести все действия до появления списка ??? Или может я не понимаю всю суть PageObjecta и мне надо описать больше классов…По сути я нахожусь на одной странице url не меняется появляются только различные формы при различных условиях.
Когда я копирую из 1 модуля во второй берет злость)) я понимаю, что так делать нельзя, но пока не могу сообразить как от этого избавиться…
Такими темпами в 3 модуль я планирую скопировать снова первые 10 тестов , что б дойти до списка выбора…


#17

Последовательное выполнение тестовых сценариев