@alenov
Программист

Как тестировать сервис А, который обращается к сервису Б, не поднимая локально сервиса Б (Python, Flask)?

Задача известная, но не могу найти решения в моей реализации.

Имеем следующее. Сервис А выполняет некую полезную работу. Сервис Б - аутентификатор, который на запрос от А подтверждает право на это обращение. Т.е. при запросе сервиса С к сервису А последний обращается к Б и уточняет валидность токена авторизации, который сервис С "показал" сервису А.
Нужно написать тесты для А, заменив обращение к сервису Б заглушкой. Вот схематично предметный код сервиса А.

application/api.py
from application.core inport auth

@main.route('/get_data', methods=['GET'])
@auth
def get_data():
    return '{"data": "Any data"}'


Декоратор, который проверяет валидность токена авторизации:

application/core.py
def auth(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        token = request.headers.get('X-Auth-Token')
        if not get_from_cache(token):
            res = requests.get('https://service_b.com/api/check_token?token=' + token)
            if res.status_code == 200:
                set_to_cache(token)
                return fn(*args, **kwargs)

            return Responce('{"error": "Invalid token"}', status=404)

    return wrapper


Тест для А (на базе pytest):

def test_get_data(client):
    rs = client.get("get_data", headers={'X-Auth-Token': 'some_invalid_token'})
    assert rs.status_code == 404
    rs = client.get("get_data", headers={'X-Auth-Token': 'some_valid_token'})
    assert rs.status_code == 200


Можно ли в декораторе мокнуть вызов service_b.com/api/check_token, не внося никаких изменений в код декоратора?
  • Вопрос задан
  • 91 просмотр
Решения вопроса 1
@alenov Автор вопроса
Программист
Решил задачу условным импортированием.

import importlib

def auth(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        # В переменной конфигурации EXT_API_MODULE хранится имя модуля, который содержит класс extAPI
        # для генерации вызовов к внешним API. Модулей два: ext_api.py и exp_api_test.py
        # В первом реальные обработчики для продакшена, EXT_API_MODULE="exp_api"
        # Во втором - заглушки для тестов, EXT_API_MODULE="exp_api_test"
        ext_api = importlib.import_module('application.{0}'.format(current_app.config['EXT_API_MODULE']))
        token = request.headers.get('X-Auth-Token')
        if not get_from_cache(token):
            res = ext_api.extAPI().auth_service(token)
            if res.status_code == 200:
                set_to_cache(token)
                return fn(*args, **kwargs)

            return Responce('{"error": "Invalid token"}', status=404)

    return wrapper


Всем спасибо за участие!
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
fox_12
@fox_12 Куратор тега Python
Расставляю биты, управляю заряженными частицами
На проектах которые плотно работают с внешними АПИ, я использовал mock-сервер в отдельном докер-контейнере, который имитировал реальные ответы внешнего АПИ для создания тестов:
wiremock.org
Ответ написан
dimonchik2013
@dimonchik2013
non progredi est regredi
httpbin с заглушками, ну или mock сервер какой-нибудь
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы