UnitTest в Django.

geek_ant
Команда geek_ant

Тестирование приложений Django. Часть 1.

Помимо разработки и запуска приложения, есть еще один важный аспект, позволяющий убедиться, что код приложения работает так, как мы ожидаем. Это обеспечивается методикой, которая называется тестированием.

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

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

Мы рассмотрим несколько тем:

1. Важность тестирования

2. Автоматизированное тестирование

3. Тестирование в Django

4. Тестирование моделей Django

5. Тестирование views Django

6. Django request

7. Классы тестовых сценариев в Django

Давайте начнем наше обучение с того, чтобы сначала узнать о важности тестирования.

Зачем нужно тестировать?

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

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

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

Вкратце, тестирование помогает нам достичь следующих целей:

1. Понять, что те или иные части приложения работают так как нужно.

2. Обеспечить совместимость на разных инфраструктурных платформах, если приложение нужно развернуть в другой операционной системе, например Linux или Windows, и т. д.

3. Поможет снизить вероятность внесения ошибки при рефакторинге кода приложения.

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

Хотя это правда, это не дает полной картины тестирования. Тестирование как метод со временем стало очень мощным, и как разработчик вы можете сократить огромное количество времени и сил, реализуя автоматизированные тесты. Итак, что же представляют собой эти автоматизированные тесты? Или, другими словами, что такое автоматизированное тестирование? Давайте узнаем!

Автоматизированное тестирование

Многократное тестирование всего приложения при изменении одного компонента может оказаться сложной задачей, особенно если это приложение состоит из большой кодовой базы. Размер кодовой базы может быть обусловлен огромным количеством функций или сложностью проблемы, которую она решает.

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

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

Автоматизированное тестирование можно разделить на пять различных типов:

1. Модульное тестирование (Unit Test): в этом типе тестирования проверяются отдельные единицы кода. Например, модульный тест может быть нацелен на один метод или один API. Этот вид тестирования проводится для того, чтобы убедиться, что основные блоки приложения работают как положено.

2. Интеграционное тестирование: В этом типе тестирования отдельные изолированные единицы кода объединяются для формирования логической группировки. После того, как эта группировка сформирована, выполняется тестирование этой логической группы, чтобы убедиться, что группа работает так, как ожидалось.

3. Функциональное тестирование: в этом виде тестирования проверяется общая функциональность различных компонентов приложения. Это могут быть различные API, пользовательские интерфейсы и многое другое.

4. Smoke testing: В этом виде тестирования проверяется стабильность развернутого приложения, чтобы убедиться, что приложение продолжает оставаться функциональным, когда пользователи взаимодействуют с ним, не вызывая сбоя.

5. Регрессионное тестирование: Этот вид тестирования проводится для того, чтобы убедиться, что изменения, вносимые в приложение, не ухудшают ранее созданную функциональность приложения.

Как мы видим, тестирование — это большая область, для освоения которой требуется время. На эту тему написаны целые книги. Чтобы убедиться в том, что мы выделили важные аспекты тестирования, в этой главе мы сосредоточимся на аспекте модульного тестирования(Unit Test).

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

Django — это многофункциональный фреймворк, целью которого является ускорение разработки веб-приложений. Он также предоставляет полнофункциональный способ тестирования приложений.

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

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

Реализация тест-кейсов

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

Unit тесты в Django

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

1. Класс TestCase, который обертывает различные тестовые случаи, сгруппированные для данного модуля

2. Реальный тестовый случай, который необходимо выполнить для проверки потока определенного компонента

Класс, реализующий модульный тест, должен наследоваться от класса TestCase, предоставляемого тестовым модулем Django. По умолчанию Django предоставляет файл tests.py в каждой директории приложения, который можно использовать для хранения тестовых сценариев для модуля приложения.

Прим.переводчика.

Еще можно организовать хранение тестов вот таким способом:

В каждом приложении можно создать свой Python Package  и организовать структуру как на скрине. Для вью, моделей и форм - свой файл. Важно, чтобы название начиналось с test.
В каждом приложении можно создать свой Python Package  и организовать структуру как на скрине. Для вью, моделей и форм - свой файл. Важно, чтобы название начиналось с test.

После того, как эти модульные тесты будут написаны, их можно легко выполнить, запустив их напрямую с помощью предоставленной команды test в manage.py , как показано ниже:

python manage.py test

Теперь давайте рассмотрим, как инструкции assert могут помочь нам создать unit тесты и проверить ожидаемое поведение.

Про assert можно почитать в книге Д.Бэйдера - Чистый Python.

Команда geek_ant

Использование assert

Важной частью написания тестов является проверка того, пройден ли тест или нет. Как правило, для реализации таких решений в тестовой среде мы используем так называемые утверждения(assertions).

Assertions— это распространенная концепция в тестировании программного обеспечения. Они принимают два операнда и проверяют, совпадает ли значение операнда слева со значением операнда справа . Если значение слева совпадает со значением справа, утверждение считается успешным, тогда как если значения отличаются, утверждение считается невыполненным.

Утверждение, которое имеет значение False, по сути, приводит к тому, что тестовый случай оценивается как сбой, о чем затем сообщается пользователю.

Assertions в Python довольно просты в реализации, и они используют простое ключевое слово под названием assert. Например, в следующем фрагменте кода показано очень простое утверждение:

assert 1 == 1

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

1. Создайте файл test.py

2. Импортируйте модуль unittest

import unittest

После того, как модуль был импортирован, мы можем создать класс, имя которого начинается с Test и который наследуется от класса TestCase, предоставленного модулем unittest:

class TestMyModule(unittest.TestCase): def test_method_a(self): assert 1 == 1

Только если класс TestMyModule унаследует класс TestCase, Django сможет запустить его автоматически с полной интеграцией с фреймворком. После того, как класс определен, мы можем реализовать новый метод внутри класса с именем test_method_a(), который проверяет утверждение.

Здесь важно отметить схему именования тестовых классов и тестовых функций. Реализуемые тесты должны иметь префикс имени Test, чтобы модули выполнения тестов могли определить их как тесты. Это же правило относится и к методам тестирования. Начало названия метода или класса должно начинаться с test .

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

python manage.py test

или если вы используете Pycharm:

Рядом с классом и методом должен быть значок запуска. Если его нет, то проверьте настройки пайчарма: Settings --> Tools --> Python Integrated Tools. 
Рядом с классом и методом должен быть значок запуска. Если его нет, то проверьте настройки пайчарма: Settings --> Tools --> Python Integrated Tools. 

Найдите раздел Testing и укажите:

Unittests
Unittests

В любом случае, команда python manage.py test в терминале сработает.

Будем считать, что мы получили наше базовое понимание реализации тестов, давайте напишем очень простой модульный тест, чтобы получить представление о том, как ведет себя фреймворк модульного тестирования внутри Django

Упражнение 1 – написание простого модульного теста.

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

Чтобы начать работу, откройте файл tests.py в приложении вашего проекта Django. По умолчанию этот файл будет содержать только одну строку, которая импортирует класс TestCase Django из тестового модуля:

from django.test import TestCase

Добавьте код в файл tests.py, который вы только что открыли

class TestSimpleComponent(TestCase): def test_basic_sum(self): assert 1+1 == 2

Наш класс начинается с Test, наш метод начинается с test - все отлично. В нашем классе мы наследуемся от класса TestCase, предоставляемого тестовым модулем Django. Оператор assert будет сравнивать выражение слева с выражением справа. Попробуем выполнить тест:

py manage.py test
Ran 1 test in 0.001s OK Destroying test database for alias 'default'...

Получим вот такой результат. Это означает, что Django выполнил 1 тест, который успешно прошел.

Попробуйте изменить условие с assert 1+1 == 2 на assert 1+1 == 3 и снова выполните тесты, тест будет провален. Утверждение не верно.

Типы assert

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

Ранее мы уже написали простой модульный тест и кратко столкнулись с одним из assert: assert 1+1 == 2 .

Этот простой пример использует ключевое слово Python - assert.

Существует несколько различных типов assert, которые могут быть проверены внутри модульного теста при использовании библиотеки unittest. Давайте рассмотрим их:

  • assertIsNone: это утверждение используется для проверки того, имеет ли выражение значение None или нет. Например, этот тип утверждения можно использовать в случаях, когда запрос к базе данных возвращает значение None из-за отсутствия записей для указанных критериев фильтрации
  • assertIsInstance: Это утверждение используется для проверки того, соответствует ли предоставленный объект экземпляру предоставленного типа. Например, это утверждение можно использовать для проверки того, действительно ли значение, возвращаемое методом, относится к определенному типу, такому как List, Dict, Tuple и т. д.
  • assertEquals: Это очень простая функция, которая принимает два аргумента и проверяет, равны ли предоставленные ей аргументы по значению или нет. Это может быть полезно, когда вы планируете сравнивать значения структур данных, которые не гарантируют упорядоченность.
  • assertRaises: Этот метод используется для проверки того, вызывает ли имя метода, предоставленное ему при вызове, указанное исключение или нет. Это полезно, когда мы пишем тесты, в которых необходимо протестировать путь кода, вызывающий исключение. Например, такой тип утверждения может быть полезен, когда мы хотим убедиться, что исключение создается методом, выполняющим запрос к базе данных, если соединение с базой данных еще не установлено.

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

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

UnitTest в Django.

Источник: Web Development with Django

Перевод и адаптация: geek_ant

Начать дискуссию