Unittest в Django: тестирование URLs

Структура адресов проекта Todo

В проекте Todo всего пять шаблонов URL.

Адреса приложения deals:

  • главная страница /
  • список запланированных дел: страница /task/
  • вывод подробной информации о задаче: страница /task/<slug:slug>/
  • страница с сообщением об успешном добавлении задачи через форму: страница /added/

Приложение staticpages управляет статическими информационными страницами. В проекте Todo создана лишь одна такая страница: /about/.

Что тестировать в test_urls.py?

  1. Страницы доступны по ожидаемому адресу.
  2. Для страницы вызывается ожидаемый HTML-шаблон.
  3. Если у пользователя нет прав для просмотра страниц — они недоступны; происходит переадресация на ожидаемую целевую страницу.

Тестирование staticpages

Код приложения staticpages не просто лаконичный, а очень лаконичный. Протестировать его будет несложно.

# staticpages/urls.py
from django.urls import path

from .views import About


app_name = 'staticpages'

urlpatterns = [
    path('', About.as_view(), name='about'),
] 

Файлы для тестов приложения сохранены в директории staticpages/tests.

└── staticpages
    ├── __init__.py
    ├── tests
    │   ├── __init__.py  
    │   ├── test_forms.py   
    │   ├── test_models.py      
    │   ├── test_views.py   
    │   └── test_urls.py    # Тесты адресов 
    ├── admin.py
    ├── forms.py
    ├── models.py
    └── views.py 

Тесты URL в staticpages

Страницы в staticpages доступны любому пользователю. Единственное, что можно проверить в при тестировании URL в этом приложении — что страница /about/ доступна по ожидаемому адресу.

Эта проверка может выглядеть так:

# staticpages/tests/test_urls.py
from django.test import TestCase, Client


class StaticPagesURLTests(TestCase):
    def setUp(self):
        # Создаем неавторизованый клиент
        super().setUpClass()
        self.guest_client = Client()

    def test_about_url_exists_at_desired_location(self):
        """Проверка доступности адреса /page/about/."""
        response = self.guest_client.get('/page/about/')
        self.assertEqual(response.status_code, 200)

    def def test_about_url_uses_correct_template(self):
        """Проверка шаблона для адреса /page/about/."""
        response = self.guest_client.get('/page/about/')
        self.assertTemplateUsed(response, 'staticpages/about.html') 

В тесте создан клиент и проверяется, что при запросе к странице возвращается код 200. Примерно то же мы делали в smoke-тесте проекта Yatube.

Разумеется, если статических страниц будет больше одной, для их проверки хорошей идеей будет использовать subTests().

Тесты приложения deals

В проекте Todo создать новую задачу может любой посетитель, а просмотр списка задач и подробного описания каждой задачи доступно только авторизованным пользователям.Этими страницами управляет приложение deals. В нём нужно протестировать:

  • доступность всех URL приложения для авторизованного пользователя;
  • недоступность страниц /task/ (список задач) и /task/<slug:slug>/ (полное описание отдельной задачи) для неавторизованного пользователя;
  • перенаправление неавторизованного пользователя на страницу логина при попытке зайти на страницы /task/ и /task/<slug:slug>/.
# deals/urls.py
from django.urls import path

from .views import Home, TaskList, TaskDetail, TaskAddSuccess

app_name = 'deals'

urlpatterns = [
    path('', Home.as_view(), name='home'),
    path('added/', TaskAddSuccess.as_view(), name='task_added'),
    path('task/', TaskList.as_view(), name='task_list'),
    path('task/<slug:slug>/', TaskDetail.as_view(), name='task_detail'),    
] 

Тестирование общедоступных страниц

Для начала через неавторизованный клиент протестируем доступность домашней страницы и страницы с сообщением об отправке формы.Первым делом — фикстуры в методе setUp():

from django.test import TestCase, Client


class TaskURLTests(TestCase):
    def setUp(self):
        # Создаем неавторизованный клиент
        self.guest_client = Client()
        )

    # Проверяем общедоступные страницы
    def test_home_url_exists_at_desired_location(self):
        """Страница / доступна любому пользователю."""
        response = self.guest_client.get('/')
        self.assertEqual(response.status_code, 200)

    def test_task_added_url_exists_at_desired_location(self):
        """Страница /added/ доступна любому пользователю."""
        response = self.guest_client.get('/added/')
        self.assertEqual(response.status_code, 200) 

Тесты доступности страниц для авторизованного пользователя и редиректов для неавторизованного

Для тестирования страниц task/ (полный список задач) и task/<slug:slug>/ (детальная информация об отдельной задаче) надо провести подготовку:

  • создать запись в модели Task, в результате в проекте появится страница с описанием задачи task/<slug:slug>/;
  • создать запись в модели User — чтобы авторизовать клиент;
  • создать веб-клиент с авторизованным пользователем.
from django.contrib.auth import get_user_model
from django.test import TestCase, Client

from deals.models import Task

User = get_user_model()


class TaskURLTests(TestCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        # Создадим запись в БД для проверки доступности адреса task/test-slug/
        Task.objects.create(
            title='Тестовый заголовок',
            text='Тестовый текст',
            slug='test-slug'
        )

    def setUp(self):
        # Создаем неавторизованный клиент
        self.guest_client = Client()
        # Создаем пользователя
        self.user = User.objects.create_user(username='HasNoName')
        # Создаем второй клиент
        self.authorized_client = Client()
        # Авторизуем пользователя
        self.authorized_client.force_login(self.user)

    def test_home_url_exists_at_desired_location(self):
        """Страница / доступна любому пользователю."""
        response = self.guest_client.get('/')
        self.assertEqual(response.status_code, 200)

    def test_task_added_url_exists_at_desired_location(self):
        """Страница /added/ доступна любому пользователю."""
        response = self.guest_client.get('/added/')
        self.assertEqual(response.status_code, 200)

    # Проверяем доступность страниц для авторизованного пользователя
    def test_task_list_url_exists_at_desired_location(self):
        """Страница /task/ доступна авторизованному пользователю."""
        response = self.authorized_client.get('/task/')
        self.assertEqual(response.status_code, 200)

    def test_task_detail_url_exists_at_desired_location_authorized(self):
        """Страница /task/test-slug/ доступна авторизованному
        пользователю."""
        response = self.authorized_client.get('/task/test-slug/')
        self.assertEqual(response.status_code, 200)

    # Проверяем редиректы для неавторизованного пользователя
    def test_task_list_url_redirect_anonymous(self):
        """Страница /task/ перенаправляет анонимного пользователя."""
        response = self.client.get('/task/')
        self.assertEqual(response.status_code, 302)

    def test_task_detail_url_redirect_anonymous(self):
        """Страница /task/test-slug/ перенаправляет анонимного
        пользователя.
        """
        response = self.client.get('/task/test-slug/')
        self.assertEqual(response.status_code, 302) 

В Django можно проверить предположение, что с определённого адреса происходит редирект на другую страницу: метод assertRedirects позволяет одновременно протестировать

  • статус ответа запрошенной страницы;
  • статус ответа страницы, на которую ожидается редирект.

В функции test_unauthorized_user_newpage() вместо метода assertEqual лучше применить assertRedirects:

# Проверяем редиректы для неавторизованного пользователя
    def test_task_list_url_redirect_anonymous_on_admin_login(self):
        """Страница по адресу /task/ перенаправит анонимного
        пользователя на страницу логина.
        """
        response = self.guest_client.get('/task/', follow=True)
        self.assertRedirects(
            response, '/admin/login/?next=/task/'
        )

    def test_task_detail_url_redirect_anonymous_on_admin_login(self):
        """Страница по адресу /task/test_slug/ перенаправит анонимного
        пользователя на страницу логина.
        """
        response = self.client.get('/task/test-slug/', follow=True)
        self.assertRedirects(
            response, ('/admin/login/?next=/task/test-slug/')) 

Проверка вызываемых HTML-шаблонов

from django.contrib.auth import get_user_model
from django.test import TestCase, Client

from deals.models import Task

User = get_user_model()


class TaskURLTests(TestCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        # Создадим запись в БД для проверки доступности адреса task/test-slug/
        Task.objects.create(
            title='Тестовый заголовок',
            text='Тестовый текст',
            slug='test-slug'
        )

    def setUp(self):
        # Создаем неавторизованный клиент
        self.guest_client = Client()
        # Создаем пользователя
        self.user = User.objects.create_user(username='HasNoName')
        # Создаем второй клиент
        self.authorized_client = Client()
        # Авторизуем пользователя
        self.authorized_client.force_login(self.user)

    # Проверка вызываемых шаблонов для каждого адреса
    def test_home_url_uses_correct_template(self):
        """Страница по адресу / использует шаблон deals/home.html."""
        response = self.authorized_client.get('/')
        self.assertTemplateUsed(response, 'deals/home.html')

    def test_added_url_uses_correct_template(self):
        """Страница /added/ использует шаблон deals/added.html."""
        response = self.authorized_client.get('/added/')
        self.assertTemplateUsed(response, 'deals/added.html')

    def test_task_list_url_uses_correct_template(self):
        """Страница /task/ использует шаблон deals/task_list.html"""
        response = self.authorized_client.get('/task/')
        self.assertTemplateUsed(response, 'deals/task_list.html')

    def test_task_detail_url_uses_correct_template(self):
        """Страница /task/test-slug/ использует
        шаблон deals/task_detail.html.
        """
        response = self.authorized_client.get('/task/test-slug/')
        self.assertTemplateUsed(response, 'deals/task_detail.html') 

Опять получилось слишком много однородных тестов. Через subTest() будет лаконичнее и удобнее:

from django.contrib.auth import get_user_model
from django.test import TestCase, Client

from deals.models import Task

User = get_user_model()


class TaskURLTests(TestCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        # Создадим запись в БД для проверки доступности адреса task/test-slug/
        Task.objects.create(
            title='Тестовый заголовок',
            text='Тестовый текст',
            slug='test-slug'
        )

    def setUp(self):
        # Создаем неавторизованный клиент
        self.guest_client = Client()
        # Создаем пользователя
        self.user = User.objects.create_user(username='HasNoName')
        # Создаем второй клиент
        self.authorized_client = Client()
        # Авторизуем пользователя
        self.authorized_client.force_login(self.user)

    
    def test_urls_uses_correct_template(self):
        """URL-адрес использует соответствующий шаблон."""
        # Шаблоны по адресам
        templates_url_names = {
            'deals/home.html': '/',
            'deals/added.html': '/added/',
            'deals/task_list.html': '/task/',
            'deals/task_detail.html': '/task/test-slug/',
        }
        for template, adress in templates_url_names.items():
            with self.subTest(adress=adress):
                response = self.authorized_client.get(adress)
                self.assertTemplateUsed(response, template) 




Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: