Python · Testing with pytest · Expert
Testing Django Apps with pytest-django
Test Django views, models, and forms using pytest-django's built-in fixtures.
Quick topic start and explanations before exercises (exercises below):
Django Testing Patterns in Practice
#pytest-django Reference
#Exercises:
Test a Django view returns HTTP 200
## pytest.ini
# [pytest]
# DJANGO_SETTINGS_MODULE = myproject.settings
# tests/test_views.py
import pytest
@pytest.mark.django_db
def test_task_list_returns_200(client):
# call GET /tasks/ and assert status + structure
pass
Solution
# pytest.ini
# [pytest]
# DJANGO_SETTINGS_MODULE = myproject.settings
# tests/test_views.py
import pytest
@pytest.mark.django_db
def test_task_list_returns_200(client):
response = client.get('/tasks/')
assert response.status_code == 200
data = response.json()
assert 'results' in data
assert isinstance(data['results'], list)
Test model save and database persistence
#import pytest
from myapp.models import Task
@pytest.mark.django_db
def test_default_completed_is_false():
# create and retrieve fresh from DB
pass
@pytest.mark.django_db
def test_task_can_be_completed():
# create, update, save, refresh, assert
pass
Solution
import pytest
from myapp.models import Task
@pytest.mark.django_db
def test_default_completed_is_false():
task = Task.objects.create(title='New task')
task_from_db = Task.objects.get(pk=task.pk)
assert task_from_db.completed is False
@pytest.mark.django_db
def test_task_can_be_completed():
task = Task.objects.create(title='Finish report', completed=False)
task.completed = True
task.save()
task.refresh_from_db()
assert task.completed is True
Test an authenticated view with force_login
#import pytest
from myapp.models import Task
@pytest.mark.django_db
def test_my_tasks_redirects_anonymous(client):
pass
@pytest.mark.django_db
def test_my_tasks_returns_only_owners_tasks(client, django_user_model):
pass
Solution
import pytest
from myapp.models import Task
@pytest.mark.django_db
def test_my_tasks_redirects_anonymous(client):
response = client.get('/my-tasks/')
assert response.status_code == 302
@pytest.mark.django_db
def test_my_tasks_returns_only_owners_tasks(client, django_user_model):
alice = django_user_model.objects.create_user(username='alice', password='x')
bob = django_user_model.objects.create_user(username='bob', password='x')
Task.objects.create(title="Alice's task", owner=alice)
Task.objects.create(title="Bob's task", owner=bob)
client.force_login(alice)
response = client.get('/my-tasks/')
assert response.status_code == 200
results = response.json()['results']
assert len(results) == 1
assert results[0]['title'] == "Alice's task"
Override a Django setting for one test with the settings fixture
## tests/test_utils.py
import pytest
from myapp.utils import get_max_tasks
def test_get_max_tasks_with_override(settings):
pass
def test_get_max_tasks_default():
pass
Solution
# tests/test_utils.py
import pytest
from myapp.utils import get_max_tasks
def test_get_max_tasks_with_override(settings):
settings.MAX_TASKS_PER_USER = 3
assert get_max_tasks() == 3
def test_get_max_tasks_default():
assert get_max_tasks() == 10
Test a view function directly with RequestFactory
#import json
import pytest
from myapp.views import task_list, my_tasks
from myapp.models import Task
@pytest.mark.django_db
def test_task_list_with_rf(rf):
pass
@pytest.mark.django_db
def test_my_tasks_with_rf(rf, django_user_model):
pass
Solution
import json
import pytest
from myapp.views import task_list, my_tasks
from myapp.models import Task
@pytest.mark.django_db
def test_task_list_with_rf(rf):
Task.objects.create(title='First')
Task.objects.create(title='Second')
request = rf.get('/tasks/')
response = task_list(request)
assert response.status_code == 200
data = json.loads(response.content)
assert len(data['results']) == 2
@pytest.mark.django_db
def test_my_tasks_with_rf(rf, django_user_model):
user = django_user_model.objects.create_user(username='alice', password='x')
Task.objects.create(title="Alice's task", owner=user)
request = rf.get('/my-tasks/')
request.user = user
response = my_tasks(request)
assert response.status_code == 200
data = json.loads(response.content)
assert len(data['results']) == 1