Тестирование Flask-приложения
Тесты ловят поломки до пользователей. Flask даёт тестовый клиент, который шлёт запросы приложению напрямую, без реального сервера и браузера.
Тут окупается фабрика: для тестов создаёшь отдельный экземпляр приложения с тестовой базой и TESTING=True. Тестовый клиент имитирует запросы (GET, POST), а ты проверяешь статус ответа и его содержимое. Быстро, изолированно, повторяемо.
Ручная проверка «потыкать в браузере» не масштабируется: на сотом маршруте ты не вспомнишь, что проверять. Автотесты делают это за секунды и не забывают. Flask создаёт тестовый клиент методом app.test_client() — он шлёт запросы прямо в WSGI-приложение, минуя сеть.
import pytest
from blog import create_app
from blog.extensions import db
@pytest.fixture
def client():
app = create_app({"TESTING": True,
"SQLALCHEMY_DATABASE_URI": "sqlite:///:memory:"})
with app.app_context():
db.create_all()
yield app.test_client()
def test_index(client):
resp = client.get("/")
assert resp.status_code == 200
def test_create_post(client):
resp = client.post("/posts/new",
data={"title": "Тест", "body": "..."},
follow_redirects=True)
assert resp.status_code == 200
assert "Тест".encode() in resp.data
Фикстура client собирает приложение с тестовой конфигурацией: TESTING=True и база в памяти (:memory:) — она существует только во время теста и не трогает боевые данные. follow_redirects=True заставляет клиент пройти по PRG-редиректу до финальной страницы.
Автотесты — это страховка, которая позволяет менять код без страха что-то сломать незаметно. Здесь окончательно окупается фабрика: для тестов ты создаёшь отдельный экземпляр приложения с TESTING=True и базой в памяти (:memory:), полностью изолированный от боевых данных. Тестовый клиент работает без сети и браузера — он формирует WSGI-запрос и вызывает приложение напрямую, поэтому сотни тестов проходят за секунды. Хороший тест проверяет одну ситуацию, начинает с чистого состояния (свежая фикстура) и сверяет и статус-код, и содержимое ответа. И не забывай follow_redirects при тестировании POST-форм: из-за паттерна PRG без него ты получишь 302-редирект вместо финальной страницы и не сможешь проверить результат.
Как работает под капотом
Тестовый клиент не поднимает сервер. Он формирует WSGI-окружение запроса и вызывает приложение напрямую, получая объект ответа. Поэтому тесты быстрые: нет сети, нет браузера — только вызов функции.
test_client().get("/")
│ собрать фейковый запрос (WSGI environ)
▼ вызвать app(environ) напрямую (без сети)
пройти маршрут → view → ответ
▼
Response с .status_code и .data
▼ assert проверяет результат
Смоделируем тестовый клиент обычным Python поверх «приложения»-словаря маршрутов.
routes = {
("GET", "/"): lambda: (200, "Главная"),
("GET", "/about"): lambda: (200, "О нас"),
}
class TestClient:
def request(self, method, path):
view = routes.get((method, path))
if not view:
return (404, "Not Found")
return view()
def test_index():
c = TestClient()
status, body = c.request("GET", "/")
assert status == 200
assert "Главная" in body
return "test_index OK"
def test_missing():
c = TestClient()
status, _ = c.request("GET", "/none")
assert status == 404
return "test_missing OK"
print(test_index())
print(test_missing())
Запусти: клиент «шлёт» запросы и возвращает ответ, а assert проверяет статус и содержимое — ровно как настоящий test_client. Зелёные тесты = уверенность, что приложение работает.
Частые ошибки
- Тестировать на боевой базе. Используй отдельную/in-memory базу через тестовую конфигурацию фабрики.
- Забыть follow_redirects при POST. Из-за PRG ответ будет 302, а не финальные 200; проверка содержимого провалится.
- Не изолировать тесты. Каждый тест должен начинать с чистого состояния (свежая фикстура).
Best practices
- Конфигурируй тестовое приложение через аргумент фабрики (TESTING, in-memory БД).
- Один тест — одна проверяемая ситуация; имена тестов описывают сценарий.
- Проверяй и статус-код, и содержимое ответа, не что-то одно.
Что запомнить
- test_client вызывает приложение напрямую через WSGI, без сети.
- Фабрика даёт изолированный экземпляр с TESTING=True и in-memory базой.
- Каждый тест — одна ситуация, с чистого состояния.
- Проверяй и статус-код, и тело; для POST используй follow_redirects.
Итог: test_client шлёт запросы приложению напрямую, фабрика даёт изолированный экземпляр с тестовой базой, а assert проверяет статус и тело. Дальше — финальный урок: деплой в продакшен.