Что стоит тестировать в Django

Я уже неоднократно обсуждал тему тестирования. Мы говорили о том, стоит ли превращать тестирование в культ, и о том, как следует тестировать Django. Теперь осталось только рассмотреть, что именно нужно тестировать в Django, если мы всё же решили это делать.

Дисклеймер: тестируйте всё, что содержит логику.

Модели (Models)

  • Проверка создания, обновления и удаления объектов.
  • Проверка валидации полей (например, blank, null, unique).
  • Проверка методов моделей (если есть кастомная логика).
  • Проверка связей (ForeignKey, ManyToManyField).
from django.test import TestCase
from myapp.models import MyModel

class MyModelTest(TestCase):
    def test_model_creation(self):
        obj = MyModel.objects.create(name="Test")
        self.assertEqual(obj.name, "Test")

Представления (Views)

  • Проверка HTTP-ответов (status_code, template_used, redirects).
  • Проверка контекста (передаваемых в шаблон данных).
  • Проверка работы с аутентификацией и правами (@login_required, @permission_required).
  • Проверка обработки форм и валидации.
from django.test import TestCase, Client

class MyViewTest(TestCase):
    def setUp(self):
        self.client = Client()

    def test_home_page_status(self):
        response = self.client.get('/')
        self.assertEqual(response.status_code, 200)

Формы (Forms)

  • Проверка валидации данных.
  • Проверка кастомных методов форм.
  • Проверка ошибок при неверных данных.
from django.test import TestCase
from myapp.forms import MyForm

class MyFormTest(TestCase):
    def test_valid_form(self):
        form = MyForm(data={"name": "Test", "email": "test@example.com"})
        self.assertTrue(form.is_valid())

API (DRF, если используется)

  • Проверка сериализаторов.
  • Проверка эндпоинтов (GET, POST, PUT, DELETE).
  • Проверка прав доступа (permissions).
from rest_framework.test import APITestCase
from rest_framework import status

class MyApiTest(APITestCase):
    def test_get_request(self):
        response = self.client.get('/api/my-endpoint/')
        self.assertEqual(response.status_code, status.HTTP_200_OK)

Шаблоны (Templates)

  • Проверка корректного отображения данных.
  • Проверка условий (if, for в шаблонах).
from django.test import TestCase

class TemplateTest(TestCase):
    def test_template_used(self):
        response = self.client.get('/')
        self.assertTemplateUsed(response, 'index.html')

Сигналы (Signals)

  • Проверка выполнения логики при срабатывании сигналов (post_save, pre_delete и т. д.).
from django.test import TestCase
from django.db.models.signals import post_save
from myapp.models import MyModel
from myapp.signals import my_signal_handler

class SignalTest(TestCase):
    def test_signal(self):
        post_save.connect(my_signal_handler, sender=MyModel)
        obj = MyModel.objects.create(name="Test")
        # Проверка, что обработчик выполнил нужные действия

Утилиты и хелперы (Utils/Helpers)

  • Тестирование вспомогательных функций, не связанных напрямую с Django.
from django.test import TestCase
from myapp.utils import my_helper

class UtilsTest(TestCase):
    def test_helper(self):
        result = my_helper(2, 3)
        self.assertEqual(result, 5)

Команды управления (Management Commands)

  • Проверка кастомных команд (python manage.py mycommand).
from django.core.management import call_command
from django.test import TestCase
from io import StringIO

class CommandTest(TestCase):
    def test_my_command(self):
        out = StringIO()
        call_command('mycommand', stdout=out)
        self.assertIn("Success", out.getvalue())

Middleware (если есть кастомная логика)

  • Проверка изменения запросов/ответов.
from django.test import TestCase, RequestFactory
from myapp.middleware import MyMiddleware

class MiddlewareTest(TestCase):
    def test_middleware(self):
        request = RequestFactory().get('/')
        middleware = MyMiddleware(lambda r: None)
        processed_request = middleware(request)
        self.assertIn("custom_header", processed_request.META)

Интеграционные тесты (API, внешние сервисы, Celery)

  • Проверка взаимодействия с внешними API (можно мокать requests).
  • Проверка асинхронных задач (Celery).
from unittest.mock import patch
from django.test import TestCase

class ExternalAPITest(TestCase):
    @patch('requests.get')
    def test_api_call(self, mock_get):
        mock_get.return_value.status_code = 200
        response = my_api_call()
        self.assertEqual(response.status_code, 200)