Доступ к параметрам прибора pytest с областью действия класса при заказе параметризованных тестов

#python #selenium #pytest

Вопрос:

введите описание изображения здесьДля моего тестирования селена с помощью pytest у меня есть следующая логика в conftest.py файл

     import pytest
    from selenium import webdriver
    from webdriver_manager.chrome import ChromeDriverManager
    from webdriver_manager.firefox import GeckoDriverManager
    
    @pytest.fixture(params=["Chrome","Firefox"],scope='class')
    def oneTimeSetup1(request):
        if request.param == "Chrome":
            driver = webdriver.Chrome(ChromeDriverManager().install())
        if request.param == "Firefox":
            driver = webdriver.Firefox(executable_path=GeckoDriverManager().install())
    
        driver.implicitly_wait(5)
        driver.maximize_window()
        driver.get("https://courses.letskodeit.com/practice")
    
        if request.cls is not None:
            request.cls.driver = driver
        print("the velue of param is "   request.param)

    
        yield driver
        driver.quit()
 

моя структура теста такова

 dir tests
--conftest.py
--test_one.py
----TestClassOne
------test_one
------test_two
 

когда я соберу тест, я смогу увидеть ниже

 <Package tests>
  <Module test_one.py>
    <Class TestClassOne>
        <Function test_one[Chrome]>
        <Function test_one[Firefox]>
        <Function test_two[Chrome]>
        <Function test_two[Firefox]>
 

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

Можем ли мы провести один сеанс браузера Chrome, который выполнит как my test_one и test_two, так и то же самое для firefox.

 import pytest
from pages.page1 import Page1


@pytest.mark.usefixtures("oneTimeSetup1")
class TestClassOne():

    @pytest.fixture(autouse=True)
    def classObject(self):
        self.page = Page1(self.driver)

    @pytest.mark.run(order=1)
    def test_one(self):
        self.page.methodA()
        print("This is Test One")

    @pytest.mark.run(order=2)
    def test_two(self):
        self.page.methodC()
        print("This is Test Two")
 

Комментарии:

1. Да, я вижу, что браузер вызывается в общей сложности 4 раза. Разве он не должен позвонить дважды? Один раз с браузером = Chrome amp; браузер = Firefox??

2. Я добавляю печать(«значение параметра равно» request.param) в oneTimeSetup1. Я прикрепил скриншот CLI. Для каждой из тестовых функций вызывается новый сеанс браузера.

3. Хорошо, теперь я могу воспроизвести проблему — это связано с pytest-ordering (я не установил ее при первой попытке). Кажется, это нарушает рамки. Поскольку мне посчастливилось сохранить pytest-order преемника pytest-ordering (который больше не поддерживается), я напишу для этого ошибку. Попробуйте пока удалить run метки и проверьте, происходит ли это по-прежнему.

4. Спасибо, работает как заклинание после удаления @pytest.mark.run. Есть ли какой-либо другой способ сохранить порядок тестов? Я надеюсь, что они исправят эту проблему в следующем выпуске pytest-заказа.

5. Проблема здесь в параметризованных тестах — упорядочение тестов приведет к объединению параметризованных тестов, в то время как область действия класса будет делать обратное. Я подумаю об этом… Как я уже писал, я утверждаю pytest-order , что «они» были бы мной в этом случае. Я посмотрю, что я могу сделать, хотя мне пока немного неясно, потому что параметризация и упорядочение в области классов здесь несколько противоречат друг другу.

Ответ №1:

Как упоминалось в комментариях, проблема связана с заказом через pytest-ordering плагин. На самом деле это ожидаемое поведение (а не ошибка, как я писал изначально), потому что тесты четко упорядочены, и этот порядок выполняется после любого первоначального заказа из-за использования прибора.

Есть возможность изменить это поведение, если использовать pytest-порядок (вилку pytest-порядка, которая больше не поддерживается) с опцией —снисходительный-порядок. Это изменяет последовательность заказа, так что тесты сначала упорядочиваются плагином, а затем устройством. Обратите внимание, что в этом случае вам нужно изменить маркер заказа с run на order :

 ...
    @pytest.mark.run(order=2)
    def test_one(self):
        self.page.methodA()
        print("This is Test One")

    @pytest.mark.order(1)
    def test_two(self):
        self.page.methodC()
        print("This is Test Two")
 

(Я изменил заказ, чтобы показать, что заказ имеет какое-либо действие). Если запустить это без опции, вы получите (как видно из исходного вопроса):

 $ python -m pytest --collect-only
<Package tests>
  <Module test_one.py>
    <Class TestClassOne>
        <Function test_two[Chrome]>
        <Function test_two[Firefox]>
        <Function test_one[Chrome]>
        <Function test_one[Firefox]>
 

С помощью этой --indulgent-ordering опции вы получаете вместо:

 $ python -m pytest --collect-only --indulgent-ordering
<Package tests>
  <Module test_one.py>
    <Class TestClassOne>
        <Function test_two[Chrome]>
        <Function test_one[Chrome]>
        <Function test_two[Firefox]>
        <Function test_one[Firefox]>
 

что позволяет приспособлению правильно работать как приспособление с привязкой к классу.

Как обычно, вы можете добавить эту опцию в свой pytest.ini , если хотите, чтобы она была эффективной для всех тестов:

 [pytest]
addopts = --indulgent-ordering
 

Отказ от ответственности:
Я автор pytest-order книги .