Tastypie and pytest
Tastypie offers a ResourceTestCaseMixin
which can be inherited in conjunction with the Django TestCase
to allow unit testing Tastypie endpoints in a unittest style manner. However if wanting to use pytest instead of unittest in order to take advantages of its features such as fixtures, I found a different approach had to be taken.
Although pytest supports using fixtures inside classes, I could not get them to work in conjunction with the Tastypie ResourceTestCaseMixin
. The solution I found was to avoid using ResourceTestCaseMixin
and Django’s TestCase
entirely, and instead use only top level functions with pytest decorators, and fixtures that pull in the necessary extras.
import pytest
from tastypie.test import TestApiClient
from tastypie.serializer import Serializer
from tastypie.models import ApiKey
from django.contrib.auth.models import User
@pytest.fixture(scope='function'):
def api_client():
return TestApiClient()
@pytest.fixture(scope='function'):
def serializer():
return Serializer()
@pytest.fixture(scope='function'):
def auth():
username = 'username'
password = 'password'
email = 'hello@somewhere.com'
user = User.objects.create_user(username, email, password)
user.save()
api_key, _ = ApiKey.objects.get_or_create(user=user)
api_key.save()
# Taken from `ResourceTestCaseMixin().create_apikey`, which unfortunately is
# not a static method even though it does not use `self`, otherwise we could
# just call it directly from here.
credentials = 'ApiKey %s:%s' % (username, api_key.key)
return {
'user': user,
'api_key': api_key,
'credentials': credentials,
}
import pytest
@pytest.mark.django_db
def test_authentication_failure(api_client):
"""Test that an unauthenticated response is rejected
"""
response = api_client.get(
'/api/v1/my-endpoint/',
format='json',
authentication=None,
)
assert response.status_code == 401
@pytest.mark.django_db
def test_authentication_success(api_client, auth, serializer):
"""Test that a correctly authenticated response is accepted
"""
response = api_client.get(
'/api/v1/my-endpoint/',
format='json',
authentication=auth['credentials'],
)
assert response.status_code == 200
payload = serializer.deserialize(
response.content,
format=response['Content-Type'],
)
# TODO: Assert payload contents are what was expected
The create_apikey
method which was copied from Tastypie can be found here.