Лавина изменений в коде
Решение каждой задачи в проекте затрагивает код сразу нескольких файлов. С ростом сложности любое изменение в проекте начнёт порождать волны правок в функциях, шаблонах, потребует создания файлов миграции и других изменений. Небольшое исправление может привести к тому, что часть проекта просто перестанет работать — и об этом никто не узнает до тех пор, пока не пойдут жалобы от пользователей.
Выход один: досконально проверять проект после каждого обновления, каждый раз убеждаясь, что всё работает, как ожидалось. Вы уже делали это: каждый раз перед ревью вы проверяли работоспособность проекта. Сдаётся мне, джентльмены, это было тестирование!
Сценарии тестирования
Тестирование — это отдельная профессия. Специально обученные люди-тестировщики проигрывают все возможные сценарии поведения программы и пользователя и ищут ошибки в работе проекта. Ручная проверка называется мануальное тестирование (от англ. manual: «ручное»).
Вот простейший сценарий тестирования формы авторизации:
- пользователь вводит правильный логин и пароль и входит на сайт;
- пользователь вводит неправильный логин и пароль, получает отказ и видит приглашение восстановить пароль;
- пользователь вводит правильный email в форму восстановления доступа и получает письмо со ссылкой на форму изменения пароля;
- пользователь вводит неправильный email в форму восстановления доступа и получает сообщение «такой email не найден».
На основании плана тестировщики проходят по пользовательским сценариям, выполняют определённые действия и сравнивают результат с ожидаемым.Если результат отличается от ожидаемого — тестировщик пишет отчёт об ошибке, баг-репорт; опираясь на этот отчёт, спасатели спешат на помощь и фиксики всё чинят.
По итогам работы тестировщик составляет отчёт (test-report), в котором описывает, какие случаи проверены. Это увлекательная работа, сродни рыбалке или исследованию лабиринтов; но она требует усидчивости и аккуратности.
Тестирование через пользовательский интерфейс
В прошлом спринте вы сделали форму для публикации поста. Протестируйте её. Запустите локально проект Yatube.
- Выйдите из учётной записи, если вы были авторизованы. Зайдите на страницу
http://127.0.0.1:8000/create/
.
Ожидаемое поведение: при попытке входа на страницу http://127.0.0.1:8000/create/ неавторизованный пользователь перенаправлен на страницу авторизации http://127.0.0.1:8000/auth/login/?next=/create/.
Тестирование кода
Большой проект состоит из маленьких кирпичиков — методов и функций. И тестирование кода можно начинать с них.Протестируйте фрагмент кода из листинга — вызовите эту функцию с разными аргументами и проверьте, корректно ли она работает:
def movie_quotes(name):
"""Возвращает цитаты известных персонажей из фильмов."""
quotes = {
'Элли': 'Тото, у меня такое ощущение, что мы не в Канзасе!',
'Шерлок': 'Элементарно, Ватсон!',
'Дарт Вейдер': 'Я — твой отец.',
'Thomas A. Anderson': 'Меня. Зовут. Нео!',
}
# Метод словаря get() возвращает значение для указанного ключа.
# Если запрошенный ключ не найден — get() вернёт значение,
# указанное вторым аргументом.
return quotes.get(name, 'Персонаж пока не известен миллионам.')
Варианты вызова и ожидаемые результаты:
print(movie_quotes('Элли'))
# Ожидаемый результат: 'Тото, у меня такое ощущение, что мы не в Канзасе!'
print(movie_quotes('Шерлок'))
# Ожидаемый результат: 'Элементарно, Ватсон!'
print(movie_quotes('Дарт Вейдер'))
# Ожидаемый результат: 'Я — твой отец.'
print(movie_quotes('Леонид Тощев'))
# Ожидаемый результат: 'Персонаж пока не известен миллионам.'
Отлично, вы опять провели мануальное тестирование.Oops, I do it again! В своё время это случается с каждым разработчиком.
Чтобы не заставлять других разработчиков вызывать функцию и сравнивать результаты с ожидаемыми, результаты мануального тестирования можно сохранить в Docstring.
Документируй это: Docstring и Doctest
Docstring — это строковая переменная, которую размещают сразу за объявлением модуля, функции, класса или метода. Docstring принято обрамлять в три пары двойных кавычек (РЕР257). Доступ к этой переменной можно получить так: имя_функции.__doc__
.
В docstring кратко описывают объект, к которому относится эта переменная. В ней же при необходимости сохраняют результаты проведённых тестов.
Сохраните код из листинга в файл расширением .py
.
def movie_quotes(name):
"""Возвращает цитаты известных персонажей из фильмов
>>> movie_quotes('Элли')
'Тото, у меня такое ощущение, что мы не в Канзасе!'
>>> movie_quotes('Шерлок')
'Элементарно, Ватсон!'
>>> movie_quotes('Дарт Вейдер')
'Люк, я — твой отец.'
>>> movie_quotes('Леонид Тощев')
'Персонаж пока не известен миллионам.'
"""
quotes = {
'Элли': 'Тото, у меня такое ощущение, что мы не в Канзасе!',
'Шерлок': 'Элементарно, Ватсон!',
'Дарт Вейдер': 'Люк, я — твой отец.',
}
return quotes.get(name, 'Персонаж пока не известен миллионам.')
В docstring функции добавлено описание результатов проведённого тестирования.Посмотрите на эти смешные ёлочки >>>
: они тут не просто так. В Python есть стандартная библиотека doctest; при запуске она ищет в docstring эти ёлочки и исполняет инструкции, следующие за ними; затем doctest сравнивает полученный результат с ожидаемым, указанным на следующей за инструкцией строке в docstring.
Теперь код под контролем: можно без опасений редактировать, расширять или рефакторить функцию, и если в результате изменений она перестанет возвращать ожидаемые результаты — разработчик немедленно узнает об этом. И не нужно будет заново вручную тестировать функцию и сверять полученные результаты с ожидаемыми.
Запустите doctest для файла с функцией movie_quotes()
: выполните команду python3 -m doctest <название файла.py>
из директории с вашим файлом.
Можно настроить и автоматический запуск тестирования: нужно импортировать doctest
в код и добавить вызов теста.
# Код с докстрингами
...
if __name__ == '__main__':
import doctest
doctest.testmod()
Теперь doctest будет запускаться автоматически при выполнении файла.
python3 <название файла.py>
# Сначала будет выполнен doctest, а затем - код файла
Если команда выполнена, но ничего не произошло — значит, все работает правильно, результаты теста, сохранённые в docstring, подтверждены.Сломайте код (например, измените географию) и заново запустите doctest.В консоли появится сообщение об ошибке:
<адрес и имя файла>line 6, in tmp.movie_quotes
Failed example:
movie_quotes('Элли')
Expected:
'Тото, у меня такое ощущение, что мы не в Канзасе!'
Got:
'Тото , у меня такое ощущение, что мы не в Симбирске!'
**********************************************************************
1 items had failures:
1 of 4 in tmp.movie_quotes
***Test Failed*** 1 failures.
Doctest обнаружил расхождение с ожидаемым результатом и указал на него.Это самый простой способ работы с doctest. Но этот пакет способен на большее; все его возможности описаны в документации: https://docs.python.org/3/library/doctest.html.
Документируйте код и сохраняйте результаты тестирования, от этого ваши коллеги будут спокойнее спать по ночам: код проверен, код работает. Кстати, о коллегах: умение писать документацию повысит ваши шансы на собеседовании.