Atique
Atique

Reputation: 55

Access pytest fixture params with class scope while ordering parametrized tests

enter image description hereFor my selenium testing using pytest, I have below logic in the conftest.py file

    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()

my test structure is

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

when I collect the test, I can see below

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

Since the scope of oneTimeSetup1 fixture is class, I am not sure why each test function is running with new browser session.

Can we have a single Chrome browser session that will execute both my test_one & test_two and then the same for 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")

Upvotes: 1

Views: 569

Answers (1)

MrBean Bremen
MrBean Bremen

Reputation: 16855

As mentioned in the comments, the problem comes from the ordering via the pytest-ordering plugin. This is actually expected behavior (and not a bug, as I wrote initially), because the tests are explicitely ordered, and this ordering is done after any initial ordering due to the fixture usage.

There is a possibility to change this behavior, if using pytest-order (a fork of pytest-ordering, which is no longer maintained) with the option --indulgent-ordering. This changes the sequence of the ordering, so that the tests are first ordered by the plugin, and afterwards by the fixture. Note that you have to change the order marker from run to order in this case:

...
    @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")

(I changed the order to show that the ordering has any effect). If run this without an option, you will get (as seen in the original question):

$ 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]>

With the --indulgent-ordering option, you get instead:

$ 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]>

which makes it possible for the fixture to properly work as a class-scoped fixture.

As usually, you can add the option to your pytest.ini if you want it to be effective for all tests:

[pytest]
addopts = --indulgent-ordering

Disclaimer:
I'm the author of pytest-order.

Upvotes: 0

Related Questions