Flask Тестирование - Динамическое тестирование всех защищенных маршрутов из чертежа. - PullRequest
0 голосов
/ 10 апреля 2020

Я хотел бы проверить, что все маршруты из чертежа защищены декоратором, требующим входа в систему.

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

Для этого я бы хотел l oop через все маршруты и методы

for rule in app.url_map.iter_rules():
    if rule.endpoint.startswith("my_blueprint"):
        response = app.test_client().get(rule)
        assert response.status_code == 401

Как вы можете видите, я должен указать метод (get, post ..) следующим образом app.test_client().get(rule).

Есть ли более динамический c способ вызова методов?

1 Ответ

3 голосов
/ 14 апреля 2020

Функция обнаружения

def blueprint_site_map(app, blueprint, all_methods=False):
    '''
    utilizes Flask's built-in rule mapper to generate a
    site-map of the application, returning a list of dicts, ex.
    {   
        'endpoint'  :   repr(Blueprint)
        'methods'   :   list
        'rule'      :   /route
    {
    '''
    reply = []
    rules = list(app.url_map.iter_rules())
    ignored_methods = set(() if all_methods else ('HEAD', 'OPTIONS'))
    rule_methods = [','.join(sorted(rule.methods - ignored_methods)) for rule in rules]
    for rule, methods in zip(rules, rule_methods):
        if (rule.endpoint != 'static') and (rule.endpoint.startswith(blueprint)):
            reply.append(dict(endpoint=rule.endpoint, methods=methods.split(','), rule=rule.rule))
    return reply

Пример вывода

>>> blueprint_site_map(app, 'my_blueprint')
[
  {
    'endpoint': 'my_blueprint.foo',
    'methods': ['GET', 'POST'],
    'rule': '/auth/foo'
  },
  {
    'endpoint': 'my_blueprint.bar',
    'methods': ['DELETE', 'GET', 'POST'],
    'rule': '/auth/bar'
  }
]

Использование

def test_my_blueprint_is_protected(client):
    from flask import current_app as app
    obj = blueprint_site_map(app, 'my_blueprint')
    for each in obj:
        for method in each['methods']:
            func = getattr(client, method)
            url = each['rule']  # *see note
            kwargs = {}         # inject headers, etc if needed
            response = func(url, **kwargs)
            assert response.status_code == 401

Следует отметить, что если вы используете какие-либо параметризованные правила URL, такие как разрешающие и /foo, и /foo/<string:s>, вам нужно будет вручную шаблонизировать или отфильтровать их. Функция blueprint_site_map будет включать в себя отдельные элементы списка для /foo и /foo/<string:s>, что при буквальном рассмотрении вызовет проблемы либо у самого тестового клиента, либо у вашего маршрута. c.

Обнаружение Функция создана таким образом, что вы можете использовать это соглашение для стольких различных чертежей, сколько необходимо, что по самой природе вашего использования соглашения Blueprint означает, что вы можете сохранять свои модульные тесты такими же модульными, как и приложение.

Ура!

...