Написание тестов для models.py

Структура моделей
В одном из приложении сайта на Django описаны две модели Group и Post.

Group - является категорией для постов.
Post - является моделью постов.
Модель Group

class Group(models.Model):

    title = models.CharField(max_length=200, verbose_name='Жанр')

    slug = models.SlugField(max_length=255, unique=True, verbose_name='Параметр')

    description = models.TextField(verbose_name='Содержание')

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = 'Жанр'
        verbose_name_plural = 'Жанры'
        ordering = ('title',)
Модель Post

class Post(models.Model):

    text = models.TextField(verbose_name='Текст поста', help_text='Введите текст поста')
    
    pub_date = models.DateTimeField(auto_now_add=True, verbose_name='Дата публикации')

    group = models.ForeignKey('Group', blank=True, null=True, on_delete=models.SET_NULL,
                              related_name='posts', verbose_name='Группа', help_text='Группа, относительно поста')

    author = models.ForeignKey(User, on_delete=models.CASCADE,
                               related_name='posts', verbose_name='Автор')

    def __str__(self):
        return self.text[:15]

    class Meta:
        verbose_name = 'Пост'
        verbose_name_plural = 'Посты'
        ordering = ('-pub_date', 'author')
Что в моделях нужно тестировать
В обязательном порядке тестами должен быть код:

  • валидация полей моделей,
  • методы по работе с моделями,
  • метаданные полей
Перед тестированием моделей необходимо создать класс группы тестов, который наследуется от класса TaskCase.

Экземпляры TestCase класса представляют логические тестовые единицы во unittest. Этот класс предназначен для использования в качестве базового класса, а конкретные тесты реализуются конкретными подклассами. Этот класс реализует интерфейс, необходимый средству запуска тестов, чтобы позволить ему управлять тестами.

Далее создаются тестовые записи в таблицах. Данный код описывается в методе setUpClass. Метод указан с декоратором @classmetod.

class PostModelTest(TestCase):

    @classmethod
    def setUpClass(self):
        super().setUpClass()
        self.user = User.objects.create_user(username='auth')
        self.group = Group.objects.create(title='Тестовая группа',
                                          slug='Тестовый слаг',
                                          description='Тестовое описание',)
        self.post = Post.objects.create(author=cls.user,
                                         text='Тестовое описание поста',)
Описание метода setUpClass
self.user = User.objects.create_user(username='auth') - создание тестового пользователя
self.group = Group.objects.create(...) - создание "записи" о категории
self.post = Post.objects.create(...) - создание "записи" о посте
Проверка заполнения verbose_name
в модели Post

    def test_title_label(self):
        '''Проверка заполнения verbose_name'''
        field_verboses = {'text': 'Текст поста',
                          'pub_date': 'Дата публикации',
                          'group': 'Группа',
                          'author': 'Автор'}
        for field, expected_value in field_verboses.items():
            with self.subTest(field=field):
                error_name = f'Поле {field} ожидало значение {expected_value}'
                self.assertEqual(
                    self.post._meta.get_field(field).verbose_name,
                    expected_value, error_name)
Описание теста test_title_label
Создается словарь с указанным заполнением полей verbose_name.

1. Запускается цикл перебора элементов словаря
2. В циклической проверке используется метод SubTest (метод subTest() устроен так, что при падении вложенного теста в отчёт будет выведено имя того поля, на котором упал тест)
3. Формирование строки описания ошибки error_name
4. Вызов метода теста assertEqual для сравнения полей поста verbose_name и элементов словаря
Проверка заполнения help_text
в модели Post

    def test_title_help_text(self):
        '''Проверка заполнения help_text'''
        field_help_texts = {'text': 'Введите текст поста',
                            'group': 'Группа, относительно поста'}
        for field, expected_value in field_help_texts.items():
            with self.subTest(field=field):
                error_name = f'Поле {field} ожидало значение {expected_value}'
                self.assertEqual(
                    self.post._meta.get_field(field).help_text,
                    expected_value, error_name)
Описание метода test_title_help_text
Создается словарь с указанным заполнением полей help_text.

1. Запускается цикл перебора элементов словаря
2. В циклической проверке используется метод SubTest
3. Формирование строки описания ошибки error_name
4. Вызов метода теста assertEqual для сравнения полей поста help_text и элементов словаря
Проверка длины вывода метода __str__ Post

    def test_models_have_correct_object_names(self):
        '''Проверка длины __str__ post'''
        error_name = f"Вывод не имеет {settings.LEN_OF_POSTS} символов"
        self.assertEqual(self.post.__str__(),
                         self.post.text[:settings.LEN_OF_POSTS],
                         error_name)
Описание метода test_models_have_correct_object_names
В модели Post используется метод __str__. Он выводит первые 15 символов текста поста. Необходимо проверить корректность вывода.

1. Используется метод asserEqual для сравнения вывода self.post.__str__() и формирование строки из поля text - self.post.text[:settings.LEN_OF_POSTS]
2. Формирование строки ошибки
3. Константа settings.LEN_OF_POSTS указана в файле настроек settings и вверху импортируется, она равна 15
Построение тестов для модели Group
В обязательном порядке тестами должен быть код:

  • валидация полей моделей,
  • методы по работе с моделями,
  • метаданные полей
По аналогии выстраиваются тесты для модели Group.

1. Тест проверяет поле verbose_name у элементов модели
2. Тест проверяет поле help_text у элементов модели
3. Проверяется метод __str__. В данном примере он возвращает заголовок title

По методологии TDD в начале Вы описываете тесты моделей по техническому заданию. Далее описываете сами модели.