I'm working on a Django app that exposes an API with the help of Django REST Framework (DRF). I've gotten to the point where I need to create a testing framework and have been poring over both the DRF and Django testing docs.
I've defined a BaseTestCase
class that sets up basic required data needed for all other test cases, as well as a ModelTestCase
class that inherits from BaseTestCase
, in order to make use of the setup performed. Here's how those look right now:
BaseTestCase
class BaseTestCase(APITestCase):
'''
This class does basic data setup required to test API endpoints
Creates 1+ users, sets the client to use that user for auth
'''
@classmethod
def create_data(cls):
'''
Create the users needed by automated tests
'''
# creates some data used by child test cases
@classmethod
def setUpClass(cls):
client = APIClient()
cls.client = client
# call the method to create necessary base data
cls.create_data()
# get a user and set the client to use their auth
user = get_user_model().objects.get(email='auto-test@test.com')
client.force_authenticate(user=user)
# cls.client = client
super(BaseTestCase, cls).setUpClass()
def test_base_data(self):
'''
This test ensures base data has been created
'''
# tests basic data to ensure it's created properly
def test_get_users(self):
'''
This test attempts to get the list of users via the API
It depends on the class setup being complete and correct
'''
url = '/api/users/'
response = BaseTestCase.client.get(url, format='json')
print(json.loads(response.content))
self.assertEqual(response.status_code, status.HTTP_200_OK)
ModelTestCase
class ModelTestCase(BaseTestCase):
@classmethod
def setUpClass(cls):
super(ModelTestCase, cls).setUpClass()
client = APIClient()
user = get_user_model().objects.all()[0]
client.force_authenticate(user=user)
cls.client = client
def test_create_model(self):
'''
Make sure we can create a new model with the API
'''
url = '/api/model/'
# set the request payload
response = ModelTestCase.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
When I run all tests, I get a failure because one of the BaseTestCase
data verification asserts (based on a count of how many objects are present) fails due to there being too many (since the BaseTestCase
has been set up twice- once on it's own, once as part of the setUpClass
of ModelTestCase
When I run only the ModelTestCase
, I get the following error:
======================================================================
ERROR: test_get_users (app.tests.ModelTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/path/to/tests.py", line 125, in test_get_users
response = BaseTestCase.client.get(url, format='json')
AttributeError: type object 'BaseTestCase' has no attribute 'client'
----------------------------------------------------------------------
Which I don't understand- shouldn't the setUpClass()
of BaseTestCase
be running as normal?
I've also tried defining the ModelTestCase
to inherit from APITestCase
- with this configuration, running all tests succeeds, but (I believe) only because tests are run alphabetically, so the BaseTestCase
runs, sets up data, and then the ModelTestCase
can make use of that data.
I'd like for the tests themselves to be independent- and I believe setUpData()
can be used for that. However, I also want the client setup (for auth) as well as data setup (which will end up being relatively expensive, I think) to be shared across test cases so that it wouldn't need to be repeated per-case, which is why I thought creating a base class to inherit from was the way to go.
Is there a way to accomplish what I've outlined? Should I be using setUpData()
instead of setUpClass()
? Or is there a way to create my BaseTestCase
class and have it not run when tests are executed?
According to Django Rest Framework Testing section, you should keep the default schema using setUp()
methods. That's how I've found a resonable solution:
from django.urls import reverse
from rest_framework.test import APITestCase
import pytest
from core.factories import UserFactory, ClientFactory, AdministratorFactory, FacilitatorFactory, ParticipantFactory
class BaseAPITestCase(APITestCase):
def setUp(self):
self.user = UserFactory()
self.client.force_authenticate(user=self.user)
class UserTestCase(BaseAPITestCase):
def setUp(self):
# Call Parent's constructor.
super(self.__class__, self).setUp()
self.clients = ClientFactory(user=self.user)
self.administrator = AdministratorFactory(user=self.user)
self.facilitator = FacilitatorFactory(user=self.user)
self.participant = ParticipantFactory(user=self.user)
def test_get_users(self):
url = reverse("api_v1:user-list")
response = self.client.get(url)
self.assertEquals(response.data["count"], 1)
self.assertEquals(response.data["results"][0]["username"], self.user.username)
self.assertEquals(response.status_code, 200)
Result:
============================================================================== test session starts ===============================================================================
platform linux -- Python 3.7.6, pytest-5.3.0, py-1.8.1, pluggy-0.13.1 --
cachedir: .pytest_cache
Django settings: tests.settings (from ini file)
Using --randomly-seed=1589794116
plugins: django-3.7.0, django-test-migrations-0.1.0, randomly-3.1.0, hypothesis-4.53.0, timeout-1.3.0, testmon-1.0.0, cov-2.8.0, deadfixtures-2.1.0
collected 1 items
tests/api/test_basics.py::UserTestCase::test_get_users PASSED
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.