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

Это упрощенный фрагмент моего кода, который использует библиотеку flask (импортированную вверху) и содержит два метода: один для маршрута «/» и один для маршрута «/about». Внизу также есть основной метод, который запускает приложение фляги.

from flask import Flask, render_template

app = Flask(__name__)


@app.route("/")
def home_page():
    return render_template("index.html")

@app.route("/about")
def about_page():
    return render_template("about.html")


if __name__ == "__main__":
    app.run(debug=False, host="0.0.0.0", port="5000")

Вот как я тестировал эти два метода с помощью pytest:

import pytest
from pytest_mock import MockFixture

@pytest.fixture
def client():
    app.config.update({"TESTING": True})

    with app.test_client() as client:
        yield client

def test_homepage(client):
    response = client.get("/")
    assert response.status_code == 200
    assert b"Welcome to the home page" in response.data

def test_about_page(client):
    response = client.get("/about")
    assert response.status_code == 200
    assert b"I am a software engineer" in response.data

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

Чтобы проверить, что приведенный ниже код

@app.route("/")
def home_page():
    return render_template("index.html")

делает то, что мы думаем, мы вызываем client.get() и передаем тестируемый маршрут в качестве аргумента методу get().

def test_homepage(client):
    response = client.get("/")

Вот и все, что касается настройки модульного теста. Это очень просто, так как тестируется только один маршрут.

Затем мы переходим к утверждению, что мы получаем 200 от тестового сервера, что имитирует реальную вещь (то есть успешный вызов маршрута!).

    assert response.status_code == 200

Наше последнее утверждение состоит в том, что то, что мы знаем, будет в ответе (то, что мы получим от сервера). В этом примере я знаю, что «Добро пожаловать на домашнюю страницу» должно быть в html маршрута «/» (поскольку в этом случае маршрут возвращает статическую страницу). Поэтому я проверяю, находится ли он в response.data.

assert b"Welcome to the home page" in response.data

Откуда взялись response.data? Это одно из многих свойств объекта ответа. Вызов .data в ответе позволяет нам увидеть ответ в виде байтов. Вот почему мы преобразуем строку b"Добро пожаловать на домашнюю страницу" в байтовый объект.

Это простой домашний маршрут.

Как насчет маршрута /about flask?

@app.route("/about")
def about_page():
    return render_template("about.html")

Шаблон для модульного теста точно такой же — мы просто добавляем соответствующий маршрут:

def test_about_page(client):
    response = client.get("/about")
    assert response.status_code == 200
    assert b"I am a software engineer" in response.data

Вам может быть интересно, почему мы не тестируем метод render_template(), который использует наш код. Это потому, что это встроенный метод библиотеки flask, а не тот, который мы написали сами.

Спасибо за чтение, я надеюсь, что это было полезно!

Официальные документы: https://flask.palletsprojects.com/en/2.3.x/testing/#sending-requests-with-the-test-client