Написание unit-тестов в Django и DRF

Замечание
Последний раз данная статья обновлялась 15.10.2022, информация может быть устаревшей.

SimpleTestCase - подкласс unittest.TestCase, с расширенной функциональностью. Есть Client. Нет работы с БД.

APISimpleTestCase - подкласс SimpleTestCase для тестирования DRF. Дополнительно использует APIClient.

TestCase - наиболее часто используемый класс для написания тестов в Django. Он наследуется от TransactionTestCase (и, соответственно, от SimpleTestCase).

  • Обертывает тесты в два вложенных блока atomic(): один для всего класса и один для каждого теста.
  • Проверяет отложенные ограничения базы данных в конце каждого теста.
  • Имеет дополнительный метод setUpTestData()

APITestCase - подкласс TestCase для тестирования DRF. Дополнительно использует APIClient.

Описанный выше блок atomic на уровне класса позволяет создавать начальные данные на уровне всего класса, один раз для всего TestCase. Эта техника позволяет ускорить тестирование по сравнению с использованием setUp().

1
2
3
4
5
6
class MyAppTests(APITestCase):

    @classmethod
    def setUpTestData(cls):
        # Set up data for the whole TestCase
        cls.foo = Foo.objects.create(bar="Test")

Изменения обектов из setUpTestData() в тестовых методах будут сохраняться между всеми тестовыми методами. Изменения можно откатить в методе setUp(), например, с помощью refresh_from_db().

После того, как мы создали файл с данными (например, в формате .json) и поместили его в каталог app/fixtures/ нашего приложения, можно использовать его в модульных тестах, указав атрибут класса fixtures в любом подклассе django.test.TestCase, например:

1
2
class MyAppTests(APITestCase):
    fixtures = ['data_only_for_tests.json', ]

Для улучшения производительности fixtures загружаются один раз для всего тестового класса. Это происходит перед вызовом setUpTestData(), а не перед каждым тестом, и использует транзакции для очистки базы данных перед каждым тестом.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class MyAppTests(APITestCase):
    fixtures = ['data_only_for_tests.json']

    @classmethod
    def setUpTestData(cls):
        cls.user_from_fixtures = User.objects.get(id=1)

    def jwt_auth(self, user):
        auth = self.client.post(
            '/api/api-token-auth/',
            {'email': user.email, 'password': self.password},
            format='json'
        )
        token = auth.data['token']
        self.client.credentials(HTTP_AUTHORIZATION='JWT {0}'.format(token))

    def test_something(self):
        user = self.user_from_fixtures
        self.jwt_auth(user=user)
        # ...

Django Rest Framework JWT Unit Test

Custom User Testing in Django

Introduction to Testing in Django and Django Rest Framework