I am using this class which creates my login test:
import pytest
from pages.loginPage import LoginPage
from utils import utilis as utils
@pytest.mark.usefixtures("test_setup")
class TestLogin():
def test_login(self):
driver=self.driver
driver.get(utils.URL)
login =LoginPage(driver)
login.enterUsername(utils.USERNAME)
login.enterPassword(utils.PASSWORD)
login.clickLogin()
I want to re-use this test as a fixture for other tests, like this:
import pytest
from pages.loginPage import LoginPage
from pages.homePage import HomePage
from utils import utilis as util
@pytest.mark.usefixtures("test_login")
class TestAddRegulation():
def test_addRegulation(self):
driver = self.driver
homepage = HomePage(driver)
homepage.clickRegulationTile()
homepage.clickAddRegulationListItem()
And this is the conftest.py
file with the test_setup
fixture:
from selenium import webdriver
import pytest
def pytest_addoption(parser):
parser.addoption("--browser", action="store",
default="chrome",
help="Type in browser name e.g.chrome OR firefox")
@pytest.fixture(scope="class")
def test_setup(request):
browser = request.config.getoption("--browser")
if browser == 'chrome':
driver = webdriver.Chrome(executable_path=
r"C:/Users/user/PycharmProjects/RCM_AutomationFramework/drivers/chromedriver.exe")
elif browser == 'firefox':
driver = webdriver.Firefox(executable_path=
r"C:/Users/user/PycharmProjects/RCM_AutomationFramework/drivers/geckodriver.exe")
driver.implicitly_wait(5)
driver.maximize_window()
request.cls.driver = driver
yield
driver.close()
driver.quit()
print("Test is finished")
I can't get this to work, even if the test_login
case is executed before the test_addRegulation
test case.
I tried marking test_login
as a fixture but it doesn't work. I can make it work if I dropped using classes.
Can I make a class method a fixture that is re-usable for other test classes?
CodePudding user response:
Fixtures can be methods defined in a class, but then they are not available outside of the class. As the pytest documentation on fixtures states:
Fixture availability is determined from the perspective of the test. A fixture is only available for tests to request if they are in the scope that fixture is defined in. If a fixture is defined inside a class, it can only be requested by tests inside that class.
(Bold emphasis mine).
This means that you have to use a plain function to define re-usable fixtures. You can still access the class used by each test, however, via the request.cls
attribute. Make sure to have the fixture take both the request
and the test_setup
scopes:
@pytest.fixture(scope="class")
def login(request, test_setup):
driver = request.cls.driver
driver.get(utils.URL)
login = LoginPage(driver)
login.enterUsername(utils.USERNAME)
login.enterPassword(utils.PASSWORD)
login.clickLogin()
Just put that fixture in your conftest.py
file. You can use a different scope, provided it doesn't exceed the class
scope of the test_setup
fixture (so your choices are class
and function
here).
You can then use that fixture with no actual test body to test the login:
@pytest.mark.usefixtures("login")
class TestLogin:
def test_login(self):
# test passes if the login fixture completes.
pass
This does seem a bit redundant, of course.
Use the fixture for other classes the same way:
@pytest.mark.usefixtures("login")
class TestAddRegulation:
def test_addRegulation(self):
# ... etc.
A quick demo (without selenium, just plain Python):
import pytest
@pytest.fixture(scope="class")
def test_setup(request):
request.cls.fixtures = ["test_setup"]
yield
print("Test is finished, fixtures used:", request.cls.fixtures)
@pytest.fixture(scope="class")
def login(request, test_setup):
# The fixtures list was created by the test_setup fixture
fixtures = request.cls.fixtures
fixtures.append("login")
@pytest.mark.usefixtures("login")
class TestLogin:
def test_login(self):
assert self.fixtures == ["test_setup", "login"]
@pytest.mark.usefixtures("login")
class TestAddRegulation:
def test_addRegulation(self):
assert self.fixtures == ["test_setup", "login"]
Running these tests with pytest -vs
(verbose mode, disabling stdout capture) produces:
...::TestLogin::test_login PASSEDTest is finished, fixtures used: ['test_setup', 'login']
...::TestAddRegulation::test_addRegulation PASSEDTest is finished, fixtures used: ['test_setup', 'login']