Reputation: 55
For 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
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