what is it?

  • Functions that can be run before/after each test which the fixture is applied to
  • Feeds data to the test
  • Usually applied in the arrange phase of testing
  • builtin fixture, examples: caplog, monkeypatch

built-in and plugin fixtures

to see a list of pytest fixtures available: pytest --fixtures

monkeypatch

pytest monkeypatch

transactional_db

akin to using Django’s TransactionTestCase

  • adds transaction support to the test
  • without it, each test is wrapped in a transaction, which is then rolled back after each test
    • no transactions are ever committed, so on_commit() never runs
  • to test code fired in an on_commit callback within pytest, you can use the transactional_db fixture
  • slow.. to just test on_commit, you can rather use the django_capture_on_commit_callbacks fixture

client

used to send requests to our Django view

tmpdir

return a temporary directory path object which is unique to each test function invocation, created as a sub directory of the base temporary directory.

settings

a django settings object which restores changes after the testrun

custom fixtures

import pytest
 
@pytest.fixture
def fixture_1():
	return 1
	
def test_example(fixture_1):
	num = fixture_1
	assert num == 1

autouse

a convenient way to make all tests automatically request them. This can cut out a lot of redundant requests

@pytest.fixture(autouse=True)
def append_first(order, first_entry):
    return order.append(first_entry)

scope

Defining a scope, changes the way it runs

import pytest
 
@pytest.fixture(scope=session)
def fixture_1():
	return 1
  • function(default) - once per test
  • class - once per class of tests
  • module - once per module
  • session - once per session

yield vs return

to run a fixture at the end of a test (yield vs return)

import pytest
 
@pytest.fixture()
def yield_fixture():
	print("Start Test Phase")
	yield 6
	print("End Test Phase")
 
def test_example(yield_fixture):
	print("run-example-1")
	assert yield_fixture == 6

conftest.py

it’s better to move custom fixtures into tests/conftest.py instead of adding it to the test_<APP> files

conftest.py
import pytest
 
from django.contrib.auth.models import User
 
@pytest.fixture()
def user_1(db):
	user = User.objects.create_user("test-user")
	print('create-user')
	return user

factory

factory to re-use fixture for, for example different user roles:

conftest.py
import pytest
 
from django.contrib.auth.models import User
 
@pytest.fixture
def new_user_factory(db):
	def create_app_user(
		username: str,
		password: str = None,
		first_name: str = "firstname",
		last_name: str = "lastname",
		email: str = "[email protected]",
		is_staff: str = False,
		is_superuser: str = False,
		is_active: str = True,
	):
		user = User.objects.create_user(
			username=username,
			password=password,
			first_name=first_name,
			last_name=last_name,
			email=email,
			is_staff=is_staff,
			is_superuser=is_superuser,
			is_active=is_active,
		)
		return user
	return create_app_user
 
@pytest.fixture
def new_user1(db, new_user_factory):
	return new_user_factory("Test_user","password","MyName")
 
@pytest.fixture
def new_user2(db, new_user_factory):
	return new_user_factory("Test_user","password", "MyName", is_staff="True")