A fixture is used:
For example, there are test_get_username()
and test_set_check_password()
in Django as shown below:
import pytest
from django.contrib.auth.models import User
@pytest.mark.django_db
def test_get_username():
user = User.objects.create_user("test-user")
user.username = "John"
assert user.get_username() == "John"
@pytest.mark.django_db
def test_set_password_and_check_password():
user = User.objects.create_user("test-user")
user.set_password("new-password")
assert user.check_password("new-password") == True
Then, you can create and use user()
with @pytest.fixture to use it many times and to simplify test_get_username()
and test_set_password_and_check_password()
as shown below:
import pytest
from django.contrib.auth.models import User
@pytest.fixture # Here
def user():
user = User.objects.create_user("test-user")
return user
@pytest.mark.django_db
def test_get_username(user): # <- user
user.username = "John"
assert user.get_username() == "John"
@pytest.mark.django_db
def test_set_password_and_check_password(user): # <- user
user.set_password("new-password")
assert user.check_password("new-password") == True
And, for example, there are fixture_1()
with yield
and test_1()
as shown below:
import pytest
@pytest.fixture
def fixture_1():
print('Before Test')
yield 6
print('After Test')
def test_1(fixture_1):
print('Running Test')
assert fixture_1 == 6
Then, this is the output below:
$ pytest -q -rP
. [100%]
=============== PASSES ===============
_______________ test_1 _______________
------- Captured stdout setup --------
Before Test
-------- Captured stdout call --------
Running Test
------ Captured stdout teardown ------
After Test
1 passed in 0.10s
In addition, you can run multiple fixtures for test_1()
and test_2()
as shown below. *My answer explains how to call a fixture from another fixture in Pytest and my answer explains how to pass parameters or arguments to a fixture in Pytest and my answer explains how to use a fixture with @pytest.mark.parametrize() and my answer explains how to use fixtures as arguments in @pytest.mark.parametrize()
:
import pytest
@pytest.fixture
def fixture_1():
return "fixture_1"
@pytest.fixture
def fixture_2():
return "fixture_2"
def test_1(fixture_1, fixture_2):
print(fixture_1, fixture_2)
assert True
def test_2(fixture_1, fixture_2):
print(fixture_1, fixture_2)
assert True
Then, this is the output below:
$ pytest -q -rP
.. [100%]
=============== PASSES ================
_______________ test_1 ________________
-------- Captured stdout call ---------
fixture_1 fixture_2
_______________ test_2 ________________
-------- Captured stdout call ---------
fixture_1 fixture_2
2 passed in 0.33s
And, you can use request.getfixturevalue() to run fixture_1()
and fixture_2()
in test_1()
and test_2()
as shown below:
import pytest
@pytest.fixture
def fixture_1():
return "fixture_1"
@pytest.fixture
def fixture_2():
return "fixture_2"
def test_1(request):
print(request.getfixturevalue("fixture_1"))
print(request.getfixturevalue("fixture_2"))
assert True
def test_2(request):
print(request.getfixturevalue("fixture_1"))
print(request.getfixturevalue("fixture_2"))
assert True
Then, this is the output below:
$ pytest -q -rP
.. [100%]
=============== PASSES ================
_______________ test_1 ________________
-------- Captured stdout call ---------
fixture_1
fixture_2
_______________ test_2 ________________
-------- Captured stdout call ---------
fixture_1
fixture_2
2 passed in 0.10s
And, you can use @pytest.fixture(autouse=True)
to run fixtures for all the tests test_1()
and test_2()
without setting fixtures as the tests' parameters as shown below. *A test cannot use fixtures' return values without fixtures' parameters:
import pytest
@pytest.fixture(autouse=True)
def fixture_1():
print("fixture_1")
@pytest.fixture(autouse=True)
def fixture_2():
print("fixture_2")
def test_1():
assert True
def test_2():
assert True
Then, this is the output below:
$ pytest -q -rP
.. [100%]
=============== PASSES ================
_______________ test_1 ________________
-------- Captured stdout setup --------
fixture_1
fixture_2
_______________ test_2 ________________
-------- Captured stdout setup --------
fixture_1
fixture_2
2 passed in 0.33s
And, you can use @pytest.mark.usefixtures for test_1()
and test_2()
to run multiple fixtures as shown below. *A test cannot use fixtures' return values without fixtures' parameters:
import pytest
@pytest.fixture
def fixture_1():
print("fixture_1")
@pytest.fixture
def fixture_2():
print("fixture_2")
@pytest.mark.usefixtures('fixture_1', 'fixture_2')
def test_1():
assert True
@pytest.mark.usefixtures('fixture_1', 'fixture_2')
def test_2():
assert True
Then, this is the output below:
$ pytest -q -rP
.. [100%]
=============== PASSES ================
_______________ test_1 ________________
-------- Captured stdout setup --------
fixture_1
fixture_2
_______________ test_2 ________________
-------- Captured stdout setup --------
fixture_1
fixture_2
2 passed in 0.33s
And, you can use @pytest.mark.usefixtures
for test_1()
and test_2()
in Test
class to run multiple fixtures as shown below. *A fixture can use request.cls.something
to pass data to the tests in a class:
import pytest
@pytest.fixture
def fixture_1(request):
request.cls.first_name = "John"
@pytest.fixture
def fixture_2(request):
request.cls.last_name = "Smith"
@pytest.mark.usefixtures('fixture_1', 'fixture_2')
class Test:
def test_1(self):
print(self.first_name, self.last_name)
assert True
def test_2(self):
print(self.first_name, self.last_name)
assert True
Then, this is the output below:
$ pytest -q -rP
.. [100%]
=============== PASSES ================
_____________ Test.test_1 _____________
-------- Captured stdout call ---------
John Smith
_____________ Test.test_2 _____________
-------- Captured stdout call ---------
John Smith
2 passed in 0.32s
And, you can use @pytest.fixture(autouse=True)
to run fixtures for all the tests test_1()
and test_2()
in Test
class without setting fixtures as the tests' parameters as shown below. *A fixture can use request.cls.something
to pass data to the tests in a class:
import pytest
@pytest.fixture
def fixture_1(request):
request.cls.first_name = "John"
@pytest.fixture
def fixture_2(request):
request.cls.last_name = "Smith"
@pytest.mark.usefixtures('fixture_1', 'fixture_2')
class Test:
def test_1(self):
print(self.first_name, self.last_name)
assert True
def test_2(self):
print(self.first_name, self.last_name)
assert True
Then, this is the output below:
$ pytest -q -rP
.. [100%]
=============== PASSES ================
_____________ Test.test_1 _____________
-------- Captured stdout call ---------
John Smith
_____________ Test.test_2 _____________
-------- Captured stdout call ---------
John Smith
2 passed in 0.33s
pytest
fixtures are a generalized way to set up/tear down a test case or a test suite, your example it indeed doesn't make much of a difference between a fixture and a regular function. Did you read through pytest fixtures: explicit, modular, scalable? This should give you an overview of what is possible to do with fixtures. – HelsieINPUT = 39
) that you can then use as input to your test functions like any other argument (eg.def test_divisible_by_3(input_value=INPUT):
)? – Mocha