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

Тестирование форм Django
Модуль тестирования unitest
Стандартная форма работает по сценарию:
  1. Данные пользователя после заполнения уходят POST запросом.
  2. Данные проверяются на корректность на сервере.
  3. Если данные валидны — они обрабатываются или записываются в базу. Пример обработки является авторизация.
  4. После отправки формы пользователь перенаправляется на страницу с сообщением об успешной отправке формы.





Необходимо проверить тестами следующие моменты:

1. Проверка доступа к форме
2. Проверка данных по полям. Поля проверяются на клиенте, но Вы можете подстраховаться и проверить валидность данных и на сервере. Вдруг забыли настроить проверку формы на "фронте"
3. Проверка записи итоговых данных после заполнения формы.
4. Проверка редиректов

Форма создание или редактирования поста

class PostForm(ModelForm):
    class Meta:
        model = Post
        fields = ['text', 'group']
        help_text = {
            'text': 'Текст поста',
            'group': 'Группа',
        }
Описание модели формы
На сайте присутствует страница с формой редактирования или создания поста. Имеет два поля:

  • Текст поста
  • Группа поста

После нажатия на кнопку добавить, пост добавляется в базу данных.
При сценарии редактирования данные формы заносятся в пост и сохраняются

Эти поля и сценарии будем проверять в тестах
Создание класса тестов и метода SetUp

from http import HTTPStatus
from django.test import Client, TestCase
from django.urls import reverse
from django.contrib.auth import get_user_model

from posts.models import Post, Group

User = get_user_model()


class PostFormTests(TestCase):

    def setUp(self):
        self.guest_client = Client()
        self.user = User.objects.create_user(username='auth')
        self.authorized_client = Client()
        self.authorized_client.force_login(self.user)
        self.group = Group.objects.create(title='Тестовая группа',
                                          slug='test-group',
                                          description='Описание')
ЗАПУСК ТЕСТОВ
В методе setUp заводятся два клиента: авторизованный и не авторизованный.
Создается тестовая группа group

    def test_create_post(self):
        '''Проверка создания поста'''
        posts_count = Post.objects.count()
        form_data = {'text': 'Текст записанный в форму',
                     'group': self.group.id}
        response = self.authorized_client.post(reverse('posts:post_create'),
                                               data=form_data,
                                               follow=True)
        error_name1 = 'Данные поста не совпадают'
        self.assertEqual(response.status_code, HTTPStatus.OK)
        self.assertTrue(Post.objects.filter(
                        text='Текст записанный в форму',
                        group=self.group.id,
                        author=self.user
                        ).exists(), error_name1)
        error_name2 = 'Поcт не добавлен в базу данных'
        self.assertEqual(Post.objects.count(),
                         posts_count + 1,
                         error_name2)

Описание метода test_create_post
1. Подсчитываем количество постов в базе
2. формируем словарь с данными для внесения в пост
3. Формируем запрос на страницу редактирования поста. Передаем данные для записи и фиксируем событие отправки данных (follow = True)
4. Формируем строку ошибки
5. Тестируем получение страницы
6. Фильтруем посты по новым данным и проверяем есть ли такой пост
7. Проверяем изменение количества постов.

Тесты проверяют поведения с различных сторон. Например у вас может добавиться пост в базу, но содержать другие данные
Проверка формы на право редактирование поста

   def test_can_edit_post(self):
        '''Проверка прав редактирования'''
        self.post = Post.objects.create(text='Тестовый текст',
                                        author=self.user,
                                        group=self.group)
        old_text = self.post
        self.group2 = Group.objects.create(title='Тестовая группа2',
                                           slug='test-group',
                                           description='Описание')
        form_data = {'text': 'Текст записанный в форму',
                     'group': self.group2.id}
        response = self.authorized_client.post(
            reverse('posts:post_edit', kwargs={'post_id': old_text.id}),
            data=form_data,
            follow=True)
        self.assertEqual(response.status_code, HTTPStatus.OK)
        error_name1 = 'Данные поста не совпадают'
        self.assertTrue(Post.objects.filter(
                        group=self.group2.id,
                        author=self.user,
                        pub_date=self.post.pub_date
                        ).exists(), error_name1)
        error_name1 = 'Пользователь не может изменить содержание поста'
        self.assertNotEqual(old_text.text, form_data['text'], error_name1)
        error_name2 = 'Пользователь не может изменить группу поста'
        self.assertNotEqual(old_text.group, form_data['group'], error_name2)

Описание метода test_can_edit_post
1. Создается пост
2. Сохраняется ссылка на пост
3. Создается вторая группа
4. Формируется словарь для внесения изменений в форму
5. Формируется запрос на редактирования поста, вызовом posts:post_edit и передачи id поста
6. Проверяется выполнения запроса HTTP равного 200
7. Проверка наличие поста с измененными данными
8. Проверяется изменение данных в полях поста: text и group
Проверка что группу можно не указывать

def test_group_null(self):
        '''Проверка что группу можно не указывать'''
        self.post = Post.objects.create(text='Тестовый текст',
                                        author=self.user,
                                        group=self.group)
        old_text = self.post
        form_data = {'text': 'Текст записанный в форму',
                     'group': ''}
        response = self.authorized_client.post(
            reverse('posts:post_edit', kwargs={'post_id': old_text.id}),
            data=form_data,
            follow=True)
        self.assertEqual(response.status_code, HTTPStatus.OK)
        error_name2 = 'Пользователь не может оставить поле нулевым'
        self.assertNotEqual(old_text.group, form_data['group'], error_name2)
Описание метода test_group_null
1. Создается пост
2. Сохраняется ссылка на пост
3. Формируется словарь для внесения изменений в форму. Группа указана пустой строкой.
4. Формируется запрос на редактирования поста, вызовом posts:post_edit и передачи id поста
5. Проверяется выполнения запроса HTTP равного 200
6. Проверка изменение поля group у поста
Проверка редиректа неавторизованного пользователя'

    def test_reddirect_guest_client(self):
        '''Проверка редиректа неавторизованного пользователя'''
        self.post = Post.objects.create(text='Тестовый текст',
                                        author=self.user,
                                        group=self.group)
        form_data = {'text': 'Текст записанный в форму'}
        response = self.guest_client.post(
            reverse('posts:post_edit', kwargs={'post_id': self.post.id}),
            data=form_data,
            follow=True)
        self.assertEqual(response.status_code, HTTPStatus.OK)
        self.assertRedirects(response,
                             f'/auth/login/?next=/posts/{self.post.id}/edit/')
Описание метода test_reddirect_guest_client
1. Создается пост
2. Формируется словарь для внесения изменений в форму.
3. Формируется запрос на редактирования поста не авторизованным пользователем
4. Проверяется выполнения запроса HTTP равного 200
5. Проверяется произошел ли редирект на страницу авторизации
Проверка запрета редактирования не авторизованного пользователя

   def test_no_edit_post(self):
        '''Проверка запрета редактирования не авторизованного пользователя'''
        posts_count = Post.objects.count()
        form_data = {'text': 'Текст записанный в форму',
                     'group': self.group.id}
        response = self.guest_client.post(reverse('posts:post_create'),
                                          data=form_data,
                                          follow=True)
        self.assertEqual(response.status_code, HTTPStatus.OK)
        error_name2 = 'Поcт добавлен в базу данных по ошибке'
        self.assertNotEqual(Post.objects.count(),
                            posts_count + 1,
                            error_name2)

Описание метода test_no_edit_post
1. Подсчитывается количества постов
2. Формируется словарь для внесения изменений в форму.
3. Формируется запрос на редактирования поста не авторизованным пользователем
5. Проверяется выполнения запроса HTTP равного 200
6. Проверяется что количество постов не увеличелось