Введение в тестирование приложений
Зачем нужны тесты
Вы поправили одну функцию — а сломалась страница в другом конце сайта. Заметите вы это не сразу, а пользователи — сразу. Автоматические тесты — код, который проверяет ваш код. Запустили команду — за секунды узнали, всё ли работает.
Тесты:
- ловят ошибки до того, как их увидят пользователи;
- позволяют смело переделывать код (рефакторить);
- служат документацией: по тесту видно, как должен работать код.
Кстати, у этого учебного сайта тоже есть тесты: они проверяют, что каждое эталонное решение проходит автопроверку.
Первый тест
При создании приложения Django уже положил файл tests.py:
from django.test import TestCase
class SimpleTests(TestCase):
def test_math(self):
self.assertEqual(2 + 2, 4)
- Тесты — методы класса-наследника
TestCase. - Имя метода обязано начинаться с
test. - Внутри — проверки
self.assert....
Запуск:
python manage.py test # все тесты проекта
python manage.py test blog # только приложение blog
python manage.py test blog.tests.PostTests.test_detail # один тест
Found 1 test(s).
Creating test database for alias 'default'...
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Каждая точка — пройденный тест, F — проваленная проверка, E — ошибка в коде.
Тестовая база данных
Django создаёт отдельную тестовую базу. Каждый тест в TestCase выполняется внутри транзакции, которая в конце откатывается. Тесты не портят ваши данные и не зависят друг от друга.
Тестовый клиент
self.client — «браузер», который умеет отправлять запросы к вашему приложению без запуска сервера:
from django.test import TestCase
from django.urls import reverse
class PageTests(TestCase):
def test_index(self):
response = self.client.get(reverse("index"))
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Hello, World!")
self.assertTemplateUsed(response, "hello/index.html")
def test_post_form(self):
response = self.client.post("/contacts/", {"email": "a@b.ru", "text": "Привет"})
self.assertRedirects(response, "/thanks/")
Полезные проверки
| Метод | Проверяет |
|---|---|
assertEqual(a, b) |
a == b |
assertTrue(x) / assertFalse(x) |
истинность |
assertIn(a, b) |
a in b |
assertRaises(Error) |
код выбрасывает исключение |
assertContains(resp, text) |
статус 200 и текст на странице |
assertNotContains(resp, text) |
текста на странице нет |
assertRedirects(resp, url) |
ответ — перенаправление на url |
assertTemplateUsed(resp, name) |
использован шаблон |
Подготовка данных: setUp
class PostTests(TestCase):
def setUp(self):
self.user = User.objects.create_user("anna", password="secret123")
self.post = Post.objects.create(title="Тест", body="Текст", author=self.user)
def test_detail(self):
response = self.client.get(self.post.get_absolute_url())
self.assertContains(response, "Тест")
def test_login_required(self):
self.client.login(username="anna", password="secret123")
response = self.client.get(reverse("blog:post_create"))
self.assertEqual(response.status_code, 200)
setUp выполняется перед каждым тестом. Для неизменяемых данных быстрее setUpTestData:
@classmethod
def setUpTestData(cls):
cls.user = User.objects.create_user("anna")
Что тестировать
- Модели: методы и свойства (
__str__,get_absolute_url, бизнес-логику). - Представления: статус ответа, использованный шаблон, наличие данных, редиректы, права доступа.
- Формы: что валидные данные проходят, а невалидные — нет.
- Граничные случаи: пустой список, несуществующий объект (404), анонимный пользователь.
Хорошая привычка — нашли баг, сначала напишите тест, который его воспроизводит, потом исправьте.
Итог
- Тесты — классы-наследники
django.test.TestCase, методы начинаются сtest. python manage.py testзапускает их на отдельной тестовой базе.self.clientотправляет запросы,assert*проверяют результат.setUp/setUpTestDataготовят данные.
Практика решено 0 из 7
Как Django находит тесты при запуске python manage.py test?
С какой базой данных работают тесты Django?
Напишите тест test_index_page: тестовый клиент открывает /,
а тест проверяет, что статус ответа 200 и на странице есть текст Hello, World!.
from django.test import TestCase
class IndexTests(TestCase):
def test_index_page(self):
response = self.client.get("/")
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Hello, World!")
Какие методы проверки (assert) есть у django.test.TestCase?
Используя reverse, проверьте, что страница поста с pk=999 (маршрут blog:post_detail)
отдаёт статус 404. Напишите тело метода test_missing_post.
from django.test import TestCase
from django.urls import reverse
class PostTests(TestCase):
def test_missing_post(self):
response = self.client.get(reverse("blog:post_detail", args=[999]))
self.assertEqual(response.status_code, 404)
Как называется метод TestCase, который выполняется перед каждым тестом и обычно создаёт тестовые данные?
Добавьте тест для своей страницы Hello, World и запустите python manage.py test. Вставьте последнюю строку вывода.
Если всё хорошо, последняя строка — OK.
OKВойдите, чтобы отмечать пройденные уроки.