Опубликован: 25.01.2016 | Уровень: для всех | Доступ: платный | ВУЗ: Российский Новый Университет
Лекция 9:

Расширение и развертывание

< Лекция 8 || Лекция 9: 1234 || Лекция 10 >

Юнит- тестирование — Автоматизация процесса тестирования приложений

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

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

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

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

Тестовый клиент

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

python manage.py shell 

Импортируйте класс Client (), создайте объект Client и получите домашнюю страницу приложения, используя запрос GET:

>>>from django.test.client import Client client = Client()
>>> response = client.get("/")
>>> print response 

X-Frame-Options: SAMEORIGIN Content-Type: text/html; charset=utf-8

<html>
<head>
<link href = "/static/css/bootstrap.min. css"
 rel="stylesheet" media="screen">
</head>
<body>
cnav class="navbar navbar-default" role="navigation">
<a class="navbar-brand" href="#">MyTweets</a>
</nav> cdiv class="container">
</div>
<nav class="navbar navbar-default navbar-fixed-bottom" role="navigation">
<p class="navbar-text navbar-right">Footer</p>
</nav>
<script src="/static/js/jquery-2.1.1.min.js"></script> 
<script src="/static/js/bootstrap.min.js"></script> 
<script src="/static/js/base.js"></script> </body> </html>

>>>

Попробуйте отправить запрос POST к представлению login. Выходные данные будут меняться в зависимости от того, предоставили ли вы правильные учетные данные или нет:

>>> print client.post('/login/',{' username': 'ваше имя',
'password': 'ваш пароль'})

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

>>> print client.login('/friend/invite/',	'yourusername',
'yourpassword')

Как вы можете видеть из интерактивного сеанса, класс Client ()предоставляет три метода:

  • get: Этот метод отправляет GET запрос к представлению. В качестве параметра принимает URL-адрес представления. Вы можете передать этому методу дополнительный словарь GET переменных.
  • post: Этот метод отправляет отправляет запрос POST в представление.Он принимает URL-адрес представления и словарь POST переменных в качестве параметров.
  • login: Этот метод отправляет GET запрос к представлению, которое доступно только для вошедших в систему пользователей .В качестве параметров она принимает URL представления, имя пользователя и пароль.

Класс Client () способен отслеживать состояние, что означает, что он сохраняет свое состояние между запросами. После того как вы вошли в систему, далее запросы будут обрабатываться при входе в систему. Объект ответа возвращается методами класса Client (), содержащими следующие атрибуты:

  • status_code: это HTTP статус ответа
  • content: это тело ответа страницы
  • template: это экземпляр шаблона, используемый для отображения страницы; Если были использованы несколько шаблонов, этот атрибут будет содержать список шаблонов объектов
  • context: это объект контекста, используемый для отображения шаблона.

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

Тестирование регистрации представления

Теперь, когда вы знакомы с классом Client (), напишем ваш первый тест. Юнит-тесты должны находиться в модуле с именем tests.py внутри каталога приложения. Каждый тест должен быть методом в классе, производном от модуля django.test.TestCase. Имя метода должно начинаться со слова test. Имея это в виду мы напишем метод теста, который пытается зарегистрировать новую учетную запись пользователя. Таким образом создайте файл с именем tests.py внутри каталога bookmarks и напечатайте в него следующее содержимое:

from django.test import TestCase
from django.test.client import Client
class ViewTest(TestCase) :
def setUp (self):
self.client = Client()
def testregisterpage(self):
data = {
'username':	'testuser',
'email':	'test_user@example.com',
'passwordl':	'passl23',
'password2‘:	'passl23'
}
response = self.client.post('/register/', data) self.assertEqual(response.status_code, 302) }

Давайте пройдемся по коду построчно:

  • Во-первых, мы импортировали классы TestCase и Client.
  • Далее мы определили класс под названием ViewTest(), который является производным от класса TestCase. Как я уже говорил ранее, все тестовые классы должен быть производными от этого базового класса.
  • После этого, мы определили метод setUp(). Этот метод вызывается, когда начинается процесс тестирования. Здесь мы создали объект клиента.
  • Наконец мы определили метод под названием test_register_page. Имя метода начинается со слова тест, указывающее, что это метод теста. Этот метод отправляет запрос POST в представление регистрации и проверяет код статуса на равенство с числом 302. Это число является HTTP статусом для перенаправления.

Как вы помните из предыдущей главы, представление регистрации перенаправляет пользователя, если запрос завершается успешно.

Мы проверили объект ответа с помощью метода assertEqual().Этот метод наследуется от класса TestCase. Это вызывает исключение, если два переданных аргументов не равны. Если возникает исключение, окружение тестирования узнает,тест не был пройден; в противном случае, если исключение не появляется, предполагается, что тест успешно пройден.

Класс TestCase предоставляет набор методов для использования в тестировании. Вот список важных методов:

  • assertEqual: Он ожидает, что два значения равны
  • assertNotEquals: Он ожидает , что два значения, будут неравны
  • assertTrue: Ожидается значение True
  • assertFalse: Ожидается значение False

Теперь, когда вы понимаете тестовый класс, давайте запустим реальный тест, выполнив команду:

python manage.py test
Результат будет примерно следующим:
Creating test database...
Creating table authmessage 
Creating table authgroup 
Creating table authuser 
Creating table authpermission 
[. ..]
Loading 1initialdata' fixtures... 

No fixtures found.
Ran 1 test in 0.170s OK
Destroying test database... 

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

Наш тест прошел успешно. Чтобы увидеть, какой будет вывод, если тест окажется не пройденным , измените представление test_register_page в файле tests.py путем удаления необходимой формы поля:

def test_register_page(self): data = {
'username1:	'test_user',
'email':	1test_user@example.com1,
'passwordl': '1',
# 'password2':	11'
}
response = self.client.post('/register/', data) self.assertEqual(response.status_code, 302)

Теперь выполните команду python manage.py test снова, чтобы увидеть результаты:

FAIL: testregisterpage (mytweets.userprofile.tests.ViewTest)
------------------------------------------------------------
Traceback (most recent call last):
File "mytweets/userprofile/tests.py", line 19, in test_ 
register_page
self.assertEqual(response.status_code, 302)
AssertionError: 200 1= 302
-------------------------------------------------------------
Ran 1 test in 0.170s 
FAILED (failures=l)

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

Существует множество других сценариев, для которых можно написать юнит-тесты:

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

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

Контрольные вопросы

  1. Для чего используется кэширование?
  2. В чем суть юнит-тестирования?
  3. Как выполнить интернационализацию проекта?
  4. Что должна содержать модель отправки приглашения?
  5. Какие строки маркируются как переводимые?

Упражнения

Упражнение 1.

Закончить перевод проекта

Упражнение 2.

Упражнение 2.

Упражнение 3.

Реализовать одну из систем кэширования для проекта

Упражнение 4.

Создать файл перевода проекта

Список тем, эссе

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

Краткие итоги

  • Ознакомились с системой интернационализации
  • Научились помечать строки как переводимые
  • Научились создавать файл перевода
  • Создали модель приглашения
  • Создали страницу приглашения
  • Изучили систему кэширования
  • Настроили систему кэширования для нашего проекта
  • Рассмотрели основы юнит-тестирования
  • Реализовали простейший юнит-тест для нашего проекта
  • Выполнили настройки для отправки приглашений
< Лекция 8 || Лекция 9: 1234 || Лекция 10 >
Константин Боталов
Константин Боталов

Вроде легкие вопросы и ответы знаю правильные, но система считает иначе и правильные ответысчитает неправильными. Приходится выполнть по несколько раз. Это я не правильно делаю или тест так составлен?

Владимир Филипенко
Владимир Филипенко

Листинг показывает в 4-ой лекции, что установлен Django 1.8.4. Тут же далее в этой лекции указаны настройки, которые воспринимает Django 1.7 и младше.

Дмитрий Молокоедов
Дмитрий Молокоедов
Россия, Новосибирск, НГПУ, 2009
Акбар Ахвердов
Акбар Ахвердов
Россия, г. Москва