Fixtures and Conftest
Fixtures are used when we want to run some code
before every test method. Instead of repeating the same code in every test we
define fixtures. Usually, fixtures are used to initialize database connections,
pass the base, URLs etc.
A function is marked as a fixture by
@pytest.fixture
Create a test file called test_multiplication.py
import pytest
@pytest.fixture
def input_data():
inputdata=5
return inputdata
def test_multi(input_data):
assert (3*input_data==15)
def test_multiply_evennos(input_data):
assert (4*input_data==21)
def test_multiply_oddno(input_data):
assert (5*input_data==25)
@pytest.fixture
def input_data():
inputdata=5
return inputdata
def test_multi(input_data):
assert (3*input_data==15)
def test_multiply_evennos(input_data):
assert (4*input_data==21)
def test_multiply_oddno(input_data):
assert (5*input_data==25)
output will be
We have fixture method called input_data, which supplies
the input to the tests.
To access the fixture function, the tests
have to mention the fixture name as input parameter.
While executing the test, you will see the fixture name as input
parameter. It then executes the fixture function and the returned value is
stored to the input parameter, which can be used by the test.
The fixture method has a scope only within that test
file it is defined. If we try to access the fixture in some other test file ,
we will get an error saying fixture ‘input_data’ not found for the test methods
in other files.
To use the same fixture for multiple test files, we
will create fixture methods in a file called conftest.py.
Conftest.py
We can define the fixture functions in this file to
make them accessible across multiple test files.
Create a new file conftest.py and add the below code.
import pytest
@pytest.fixture
def input_data():
inputdata=5
return inputdata
def input_data():
inputdata=5
return inputdata
import pytest
def test_add_even(input_data):
assert(10+input_data==16)
def test_add_even(input_data):
assert(10+input_data==16)
def test_add_odd():
assert(5+7==13)
assert(5+7==13)
Create another new test called test_subtraction.py
import pytest
def test_subtract_even(input_data):
assert(10-input_data==5)
def test_subtract_odd():
assert (7-3==4)
def test_subtract_even(input_data):
assert(10-input_data==5)
def test_subtract_odd():
assert (7-3==4)
Create another test called test_multiplication.py
import pytest
def test_multiply_even(input_data):
assert (4*input_data==20)
def test_multiply_oddno(input_data):
assert (5*input_data==25)
def test_multiply_even(input_data):
assert (4*input_data==20)
def test_multiply_oddno(input_data):
assert (5*input_data==25)
Run the tests by executing the following command
pytest -k even -v
output will be
pytest will look for the fixture in the test file
first and if fixture is not found then it will look into the conftest.py
Scope of a fixture
Fixture's scope is set to function by default(above
example test_multiplication.py is
the default fixture). To run the fixture once per module, we can add
scope="module" to the @pytest.fixture decorator.
We define scope in fixture. Scopes are of four types;
1) scope="function" - If we need to perform an action before and after
of an function of a module we use function scope (scope=“function”)
2) scope="class" - If we need to perform an action before and after
of an class of a module we use class scope (scope=“class”)
3) scope="module" - If we need to perform an action before and after
of an module we use module scope (scope=“module”)
4) scope="session" If we need to perform an action before and after for
a set of methods in a folder or project we session scope (scope=“session”). It
creates single fixture for set of methods in a project or modules in some path.
Scope at Class level
Below is the example for class level scope.
We will create conftest.py file and add below code.
import pytest
from selenium import webdriver
from selenium import webdriver
@pytest.fixture(scope="class")
def WebDriver(request):
base_url = "http://automationpractice.com/"
chromePath = "C:\\executables\\chromedriver.exe"
driver = webdriver.Chrome(executable_path=chromePath)
driver.get(base_url)
request.cls.driver=driver
yield driver
#return driver
Let us create two classes in "test_1.py"
and decorate with @pytest.mark.usefixtures("WebDriver")
import
pytest
import time
@pytest.mark.usefixtures("WebDriver")
class TestExampleone:
def test_title(self):
assert "My Store" in self.driver.title
def tests_clickOnLoginLink(self):
self.driver.find_element_by_xpath("//a[@title='Log in to your customer account']").click()
def test_Login(self):
time.sleep(2)
self. driver.find_element_by_xpath("//input[@id='email']").send_keys("abc111@gmail.com")
self.driver.find_element_by_xpath("//input[@name='passwd']").send_keys("abcd1234")
self.driver.find_element_by_xpath("//button[@type='submit' and @id='SubmitLogin']").click()
@pytest.mark.usefixtures("WebDriver")
class TestExampleTwo:
def testLogin_title(self):
assert "My Store" in self.driver.title
def testclickOnOrders(self):
time.sleep(3)
self.driver.find_element_by_xpath("(//a[@title='Dresses'])[2]").click()
assert "Dresses - My Store" in self.driver.title
import time
@pytest.mark.usefixtures("WebDriver")
class TestExampleone:
def test_title(self):
assert "My Store" in self.driver.title
def tests_clickOnLoginLink(self):
self.driver.find_element_by_xpath("//a[@title='Log in to your customer account']").click()
def test_Login(self):
time.sleep(2)
self. driver.find_element_by_xpath("//input[@id='email']").send_keys("abc111@gmail.com")
self.driver.find_element_by_xpath("//input[@name='passwd']").send_keys("abcd1234")
self.driver.find_element_by_xpath("//button[@type='submit' and @id='SubmitLogin']").click()
@pytest.mark.usefixtures("WebDriver")
class TestExampleTwo:
def testLogin_title(self):
assert "My Store" in self.driver.title
def testclickOnOrders(self):
time.sleep(3)
self.driver.find_element_by_xpath("(//a[@title='Dresses'])[2]").click()
assert "Dresses - My Store" in self.driver.title
Applying "@pytest.mark.usefixtures" to the
class is same as applying a fixture to every test methods in the class. Since
the fixture "WebDriver" has a scope defined as "class",
webdriver will be initialized only once per each class.
Request.cls.driver=driver
in conftest.py
This is done using the request parameter provided by
pytest to give the request of the current test function.
Run the test using below command
Pytest test_1 -v
Scope at session
level
A session-scoped fixture effectively has access to
all collected test items. Here is an example of a fixture function which walks
all collected tests
First create conftest.py
import pytest
from selenium import webdriver
@pytest.fixture(scope="session")
def WebDriver(request):
base_url = "http://automationpractice.com/"
chromePath = "C:\\executables\\chromedriver.exe"
driver = webdriver.Chrome(executable_path=chromePath)
session=request.node
for item in session.items:
cls=item.getparent(pytest.Class)
setattr(cls.obj,"driver",driver)
driver.get(base_url)
yield driver
from selenium import webdriver
@pytest.fixture(scope="session")
def WebDriver(request):
base_url = "http://automationpractice.com/"
chromePath = "C:\\executables\\chromedriver.exe"
driver = webdriver.Chrome(executable_path=chromePath)
session=request.node
for item in session.items:
cls=item.getparent(pytest.Class)
setattr(cls.obj,"driver",driver)
driver.get(base_url)
yield driver
import pytest
import time
import logging
logging.basicConfig(level=logging.DEBUG)
@pytest.mark.usefixtures("WebDriver")
class TestExampleone:
def test_title(self):
log=logging.getLogger("test_title")
assert "My Store" in self.driver.title
log.debug(self.driver.title)
def tests_clickOnLoginLink(self):
self.driver.find_element_by_xpath("//a[@title='Log in to your customer account']").click()
def test_Login(self):
time.sleep(2)
self. driver.find_element_by_xpath("//input[@id='email']").send_keys("abc111@gmail.com")
self.driver.find_element_by_xpath("//input[@name='passwd']").send_keys("abcd1234")
self.driver.find_element_by_xpath("//button[@type='submit' and @id='SubmitLogin']").click()
@pytest.mark.usefixtures("WebDriver")
class TestExampleTwo:
def testLogin_title(self):
assert "My account - My Store" in self.driver.title
def testclickOnOrders(self):
time.sleep(3)
self.driver.find_element_by_xpath("//a[@title='Orders']").click()
assert "Order history - My Store" in self.driver.title
we have used scope=session, using this, the fixture
will be created only once per test session and shared across several tests.
Run the test using below command
Pytest
test_sessionlevel -v
Note: we are sharing webdriver session in multiple
classes.
Comments
Post a Comment