Flask Login Pytest API

Admin Flask

Конфигурация PyTest для тестирования Flask API при использовании Flask-Login (Flask-Admin, Flask-Security) при которой тесты обходят авторизацию на сайте.

Описание проблемы

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

Код учитывает обход как @login_required для путей API, так и авторизирует пользователя при прохождении тестов. В результате flask_login.current_user.id видит указанного пользователя.

Конфигурация 1

Содержимое файла conftest.py. Этот файл используется для инициализации тестов.

import flask_login
import pytest
from app import app, db
from app.models.users import User


@pytest.fixture
def client():
    app.config["TESTING"] = True
    # Обходит @login_required
    app.config["LOGIN_DISABLED"] = True
    with app.test_client() as client:
        yield client


@pytest.fixture
def authenticated_request():
    # Решает проблему с flask_login.current_user.id:
    # AttributeError: 'AnonymousUser' object has no attribute 'id'
    # Создает авторизацию пользователя
    with app.test_request_context():
        test_user = db.session.query(User).filter_by(id=1).first()
        yield flask_login.login_user(test_user)

Содержимое файла test-category.py

import json
import pytest

from app import db
from app.models.categories import Category
from app.repositories.category import get_category_by_id

headers = {"Content-Type": "application/json"}

@pytest.mark.usefixtures("authenticated_request")
def test_category_rename(client):
    # Create test data
    user_id = 1
    cat = Category(user_id=user_id, name='Test Category')
    db.session.add(cat)
    db.session.commit()

    # Mock
    mock_name = 'Test Category New'
    mock_request_data = {
        'cat_id': cat.id,
        'name': mock_name,
    }

    # Rename category
    url = 'http://127.0.0.1:5000/categories/update/'
    client.patch(url, headers=headers, data=json.dumps(mock_request_data))

    # Check new name
    category = get_category_by_id(user_id, cat.id)
    assert category.name == mock_name

    # Clear test data
    db.session.delete(category)
    db.session.commit()

Ссылка на репозиторий в GitHub.

Конфигурация 2

Если не нужен обход авторизации во всех тестах можно обходить авторизацию в каждом отдельном тесте.

Содержимое файла conftest.py:

import pytest
from app import app, db


@pytest.fixture
def client():
    app.config["TESTING"] = True
    # Bypasses @login_required
    app.config["LOGIN_DISABLED"] = True
    with app.test_client() as client:
        yield client

Содержимое файла test_category.py:

import json
from app import db, app
from app.models.categories import Category
from app.models.users import User
from app.repositories.category import get_category_by_id

headers = {
    "Content-Type": "application/json",
}


def test_category_rename(client):
    # Create test data
    user_id = 1
    cat = Category(user_id=user_id, name='Test Category')
    db.session.add(cat)
    db.session.commit()

    # Mock
    mock_name = 'Test Category New'
    mock_request_data = {
        'cat_id': cat.id,
        'name': mock_name,
    }

    with app.test_client() as client:
        # Решает проблему с flask_login.current_user.id:
        # AttributeError: 'AnonymousUser' object has no attribute 'id'
        test_user = db.session.query(User).filter_by(id=user_id).first()

        @app.login_manager.request_loader
        def load_user_from_request(request):
            return test_user

        # Tests starts here
        url = 'http://127.0.0.1:5000/categories/update/'
        client.patch(url, headers=headers, data=json.dumps(mock_request_data))

    # Check new name
    category = get_category_by_id(user_id, 576)
    assert category.name == mock_name

    # Clear test data
    db.session.delete(category)
    db.session.commit()

Ссылка на репозиторий в GitHub.

Запуск тестов

Запуск тестов осуществляется командой:

pytest app/tests/

Дополнительные ключи:

# -s - отображает содержимое print
# -v - отображает полное название тестов
# --disable-pytest-warnings - убирает warnings summary
Метки:

English Query (запросы по теме на английском языке)

PyTest with Flask-Login and Flask-Admin

PyTest with Flask-Security

Bypasses login_required

PyTest and flask_login.current_user.id

PyTest and @login_required

Кстати, на сайте нет рекламы. У сайта нет цели самоокупаться, но если вам пригодилась информация можете задонатить мне на чашечку кофе в макдаке. Лайкнуть страницу или просто поблагодарить. Карма вам зачтется.

Добавить комментарий

Напишите свой комментарий, если вам есть что добавить/поправить/спросить по теме текущей статьи:
"Flask Login Pytest API"