Tutorial

Добавление юнит-тестирования в проект Django

PythonDjangoPython FrameworksApplicationsDevelopmentProgramming Project

Автор выбрал фонд Open Internet/Free Speech для получения пожертвования в рамках программы Write for DOnations.

Введение

Практически невозможно создавать веб-сайты, которые будут идеально работать сразу без каких-либо ошибок. По этой причине вы должны тестировать ваше веб-приложение, чтобы находить эти ошибки и упреждающе работать с ними. Чтобы повысить эффективность тестирования, очень часто используется разбивка тестов на модули, которые проверяют конкретный функционал веб-приложения. Эта практика называется юнит-тестированием. Это упрощает обнаружение ошибок, поскольку тесты фокусируются на небольших частях (юнитах) вашего проекта, никак не затрагивая другие его части.

Тестирование веб-сайта может стать сложной задачей, поскольку он включает несколько слоев логики, например обработку HTTP-запросов, валидацию форм и отрисовку шаблонов. Однако Django предоставляет набор инструментов, которые избавляют от множества проблем при тестировании веб-приложений. В Django предпочтительным способом написания тестов является использование модуля unittest Python, хотя вы можете использовать другие фреймворки для тестирования.

В этом руководстве вы выполните настройку набора тестов для вашего проекта Django и напишете юнит-тесты для моделей и представлений в вашем приложении. Вы научитесь запускать эти тесты, анализировать их результаты и искать причины падения тестов.

Предварительные требования

Прежде чем начать выполнение этого руководства, вам потребуется следующее:

Шаг 1 — Добавление набора тестов для вашего приложения Django

Набор тестов в Django — это все тест-кейсы для всех приложений в вашем проекте. Чтобы утилита тестирования Django могла обнаружить все имеющиеся тест-кейсы, вы должны записать тест-кейсы в скрипт, название которого начинается с test. На этом шаге вы должны будете создать структуру каталогов и файлов для вашего набора тестов и создать внутри пустой тест-кейс.

Если вы ознакомились с серией обучающих материалов по разработке Django, у вас в распоряжении должно быть приложение Django с именем blogsite​​​.

Давайте создадим папку для хранения всех наших скриптов тестов. Вначале необходимо активировать виртуальную среду:

  • cd ~/my_blog_app
  • . env/bin/activate

Затем перейдите в каталог приложения blogsite, в папку, которая содержит файлы models.py и views.py​​​, а затем создайте новую папку с именем tests:

  • cd ~/my_blog_app/blog/blogsite
  • mkdir tests

Далее необходимо превратить эту папку в пакет Python, добавив файл __init__.py:

  • cd ~/my_blog_app/blog/blogsite/tests
  • touch __init__.py

Теперь вы должны добавить файл для тестирования ваших моделей и другой файл для тестирования представлений:

  • touch test_models.py
  • touch test_views.py

В заключение вы создадите пустой тест-кейс в файле test_models.py: Вам нужно будет импортировать класс TestCase Django и сделать его родительским классом для вашего класса тест-кейса. В дальнейшем вы сможете добавить в этот тест-кейс методы для тестирования логики в ваших моделях. Откройте файл test_models.py:

  • nano test_models.py

Теперь добавьте в файл следующий код:

~/my_blog_app/blog/blogsite/tests/test_models.py
from django.test import TestCase

class ModelsTestCase(TestCase):
    pass

Вы успешно добавили набор тестов в приложение blogsite. Далее вам необходимо заполнить данные для пустого тест-кейса модели, которую вы создали.

Шаг 2 — Тестирование кода Python

На этом шаге вы протестируете логику кода в файле models.py. В частности, вы должны будете протестировать метод save модели Post, чтобы убедиться, что при вызове он создает корректный слаг для тайтла поста.

Давайте начнем с изучения кода, который уже находится в файле models.py для метода save модели Post:

  • cd ~/my_blog_app/blog/blogsite
  • nano models.py

Вы увидите следующее:

~/my_blog_app/blog/blogsite/models.py
class Post(models.Model):
    ...
    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.title)
        super(Post, self).save(*args, **kwargs)
    ...

Мы можем убедиться, что он проверяет, есть ли у поста, который будет сохранен, значение слага, и если нет, вызывает slugify для создания слага. Это тип логики, который вы можете захотеть протестировать, чтобы убедиться, что слаги действительно были созданы при сохранении поста.

Закройте файл.

Чтобы протестировать это, вернитесь к файлу test_models.py:

  • nano test_models.py

Затем обновите его содержимое, добавив код в выделенные части:

~/my_blog_app/blog/blogsite/tests/test_models.py
from django.test import TestCase
from django.template.defaultfilters import slugify
from blogsite.models import Post


class ModelsTestCase(TestCase):
    def test_post_has_slug(self):
        """Posts are given slugs correctly when saving"""
        post = Post.objects.create(title="My first post")

        post.author = "John Doe"
        post.save()
        self.assertEqual(post.slug, slugify(post.title))

Этот новый метод test_post_has_slug создает новый пост с именем "My first post", а затем указывает для поста автора и сохраняет пост. После этого, используя метод assertEqual из модуля unittest Python, он проверяет корректность слага для поста. Метод assertEqual проверяет, равны ли два переданных ему аргумента, что определяется оператором "==", и генерирует ошибку в противном случае.

Сохраните и закройте test_models.py.

Это пример того, что можно протестировать. Чем больше логики вы будете добавлять в ваш проект, тем больше тестов вам потребуется. Если вы добавите в метод save дополнительную логику или создадите новые методы для модели Post, вам нужно будет добавить сюда дополнительные тесты. Вы можете добавить их в метод test_post_has_slug или создать новые методы тестирования, но их имена должны начинаться с test.

Вы успешно создали тест-кейс для модели Post, где вы проверяли, что слаги создаются корректно после сохранения. На следующем шаге вы должны будете написать тест-кейс для тестирования представлений.

Шаг 3 — Использование тестового клиента Django

На этом шаге вы напишете тест-кейс, который тестирует представление с помощью тестового клиента Django. Тестовый клиент — это класс Python, который действует как шаблонный браузер, позволяя вам тестировать ваши представления и взаимодействовать с приложением Django таким же образом, как это делал бы пользователь. Вы можете получить доступ к тестовому клиенту, сославшись на self.client в ваших тестовых методах. Давайте, например, создадим тест-кейс в test_views.py. Откройте файл test_views.py​​​:

  • nano test_views.py

Затем добавьте следующее:

~/my_blog_app/blog/blogsite/tests/test_views.py
from django.test import TestCase


class ViewsTestCase(TestCase):
    def test_index_loads_properly(self):
        """The index page loads properly"""
        response = self.client.get('your_server_ip:8000')
        self.assertEqual(response.status_code, 200)

ViewsTestCase содержит метод test_index_loads_properly, который использует тестовый клиент Django для посещения стартовой страницы веб-сайта (http://your_server_ip:8000, где your_server_ip — это IP-адрес сервера, который вы используете). Затем тестовый метод проверяет, содержит ли ответ код состояния 200, который означает, что страница отправляет ответ без ошибок. В результате вы можете быть уверены, что при посещении страницы пользователем она также не будет генерировать ошибки.

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

На этом шаге вы создали тест-кейс для тестирования того, что визуализация представления стартовой страницы выполняется без ошибок. Теперь ваш набор тестов содержит два тест-кейса. На следующем шаге вы запустите их для просмотра результатов.

Шаг 4 — Запуск тестов

Теперь, когда вы завершили сборку набора тестов для проекта, пришло время запустить эти тесты и посмотреть их результаты. Чтобы запустить тесты, перейдите в папку blog (содержащую файл manage.py приложения):

  • cd ~/my_blog_app/blog

Запустите их с помощью следующей команды:

  • python manage.py test

Вы увидите примерно следующий вывод в вашем терминале:

Output
Creating test database for alias 'default'... System check identified no issues (0 silenced). .. ---------------------------------------------------------------------- Ran 2 tests in 0.007s OK Destroying test database for alias 'default'...

Этот вывод содержит две точки .., каждая из которых отображает выполненный тест-кейс. Теперь вы можете изменить test_views.py, чтобы вызвать падение теста. Сначала откройте файл с помощью следующей команды:

  • nano test_views.py

Затем измените выделенный код на следующий:

~/my_blog_app/blog/blogsite/tests/test_views.py
from django.test import TestCase


class ViewsTestCase(TestCase):
    def test_index_loads_properly(self):
        """The index page loads properly"""
        response = self.client.get('your_server_ip:8000')
        self.assertEqual(response.status_code, 404)

Здесь вы изменили код состояния с 200 на 404. Теперь снова запустите тест из каталога с файлом manage.py:

  • python manage.py test

Вывод должен выглядеть так:

Output
Creating test database for alias 'default'... System check identified no issues (0 silenced). .F ====================================================================== FAIL: test_index_loads_properly (blogsite.tests.test_views.ViewsTestCase) The index page loads properly ---------------------------------------------------------------------- Traceback (most recent call last): File "~/my_blog_app/blog/blogsite/tests/test_views.py", line 8, in test_index_loads_properly self.assertEqual(response.status_code, 404) AssertionError: 200 != 404 ---------------------------------------------------------------------- Ran 2 tests in 0.007s FAILED (failures=1) Destroying test database for alias 'default'...

Вы увидите сообщение, содержащее описание ошибки, указывающее скрипт, тест-кейс и метод, который не был выполнен. Также оно сообщает причину ошибки, в данном случае код состояния не равен 404, в форме сообщения AssertionError: 200 ! = 404. AssertionError здесь возникает в выделенной строке кода в файле test_views.py:

~/my_blog_app/blog/blogsite/tests/test_views.py
from django.test import TestCase


class ViewsTestCase(TestCase):
    def test_index_loads_properly(self):
        """The index page loads properly"""
        response = self.client.get('your_server_ip:8000')
        self.assertEqual(response.status_code, 404)

Она указывает, что утверждение является ложным, т. е. код состояния ответа (200) не соответсвует ожидаемому результату (404). Теперь вы можете видеть, что две точки .., идущие перед сообщением об ошибке, теперь превратились в . F, что говорит о том, что первый тест-кейс был пройден успешно, а второй — нет.

Заключение

В этом руководстве вы создали набор тестов в вашем проекте Django, добавили тест-кейсы для тестирования логики модели и представления,узнали, как запускать тесты, и проанализировали вывод теста. В качестве следующего шага вы можете создать новые тестовые скрипты для кода Python в других файлах помимо models.py и views.py.

Ниже представлено несколько статей, которые могут оказаться полезными при создании и тестировании сайтов с помощью Django:

Также вы можете найти на нашей странице материалов по теме Django другие руководства и проекты.

Creative Commons License