Мокающие зависимости FastAPI

Я пишу модульные тестовые примеры для своего проекта fastapi и не могу издеваться над вызовом dynamodb.

Файл_1

В этом файле есть все методы для выполнения действий DynamoDB с использованием вызовов boto3.

класс DynamoDBRepository:

  1. Вставить элемент — вставляет значение
  2. Получить элемент — возвращает значение

#Файл_2

Имеет класс AppConfig, который будет использоваться в качестве зависимости в более позднем файле.


from file_1 import DynamoDBRepository 

class AppConfig:

    def __init__(self) -> None:
        """Constructor class to instantiate dynamodb"""
        self._job_table = "Dynamo_DB_Table"
        self._region = "Table_region"
        self._dynamodb_repository = DynamoDBRepository(table=self._job_table, region=self._region) # created a object for the dynamodb class mentioned in file 1.

Файл_3:

Этот файл имеет декоратор маршрута fast_api.

from file_2 import AppConfig
@router.get(
    "/object/{object_id}"
)
def get_request(
    object_id: str,
    objects: AppConfig = Depends(AppConfig),
) -> ObjectBody:

    try:
        object_detail = objects._dynamodb_repository.get_item({"object_id": object_id})
        return object_detail["Item"]


Я пытаюсь издеваться над методом get_item в своем тестовом файле:

Файл_4

Это мой тестовый файл, в котором

client = TestClient(fast_api_app)

class MockAppConfig:


    def __init__(self) -> None:
        """Constructor class to instantiate dynamodb and lambda"""
         self._job_table = "Dynamo_DB_Table"
        self._region = "Table_region"
        self._dynamodb_repository = DynamoDBRepository(table=self._job_table, region=self._region)


def test_get_request():
    fast_api_app.dependency_overrides[AppConfig] = MockAppConfig
    MockAppConfig()._dynamodb_repository.get_item = {
         "id": "1234",
         "title": "Foo",
         "description": "Hello",
     }

        response = client.get("/objects/1234")
        assert response.status_code == 200
        assert response.json() == {
            "id": "foo",
            "title": "Foo",
            "description": "Hi",
        }

Насмешка над get_item не работает, и она по-прежнему запрашивает исходную базу данных и терпит неудачу из-за проверки учетных данных.

Я пробовал фикстуры monkeypatch и fastapi_dep, а также исправление, но почему-то насмешка над методом get_item не работает

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
197
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Будет ли работать метод насмешки get_item?

class MockDynamoDBRepository():
     def get_item(*args, **kwargs):
         return {
             "Item": {
             "id": "foo",
             "title": "Foo",
             "description": "Hi",
             }
         }

class MockAppConfig:
    def __init__(self) -> None:
        """Constructor class to instantiate dynamodb and lambda"""
         self._job_table = "Dynamo_DB_Table"
        self._region = "Table_region"
        self._dynamodb_repository = MockDynamoDBRepository(table=self._job_table, region=self._region)

def test_get_request():
    fast_api_app.dependency_overrides[AppConfig] = MockAppConfig

    response = client.get("/objects/1234")
    assert response.status_code == 200
    assert response.json() == {
            "id": "foo",
            "title": "Foo",
            "description": "Hi",
        }

Основываясь на ответе @svfat, вот как вы можете выполнить тест с помощью fastapi_dep - выберите любой из подходов к тестированию - с предложением или косвенным параметром:

class MockDynamoDBRepository():
    def __init__(self, *args, **kwargs):
        pass

    def get_item(self, *args, **kwargs):
        return {
            "Item": {
                "id": "foo",
                "title": "Foo",
                "description": "Hi",
            }
        }


class MockAppConfig:

    def __init__(self) -> None:
        """Constructor class to instantiate dynamodb and lambda"""
        self._job_table = "Mock Dynamo_DB_Table"
        self._region = "Mock Table_region"
        self._dynamodb_repository = MockDynamoDBRepository(table=self._job_table,
                                                       region=self._region)


def test_get_request_deps(fastapi_dep):
    with fastapi_dep(fast_api_app).override(
        {
            AppConfig: MockAppConfig,
        }
    ):
        response = client.get("/objects/1234")
        assert response.status_code == 200
        assert response.json() == {
            "id": "foo",
            "title": "Foo",
            "description": "Hi",
        }


@pytest.mark.parametrize(
    "fastapi_dep",
    [
        (
            fast_api_app,
            {AppConfig: MockAppConfig},
        )
    ],
    indirect=True,
)
def test_get_request_deps_indirect(fastapi_dep):
    response = client.get("/objects/1234")
    assert response.status_code == 200
    assert response.json() == {
        "id": "foo",
        "title": "Foo",
        "description": "Hi",
    }

Если вы не хотите создавать все дополнительные классы, вы можете использовать чистый фиктивный подход следующим образом:

from mock.mock import MagicMock

def test_get_request_deps_mock(fastapi_dep):
    my_mock = MagicMock()
    my_mock._dynamodb_repository.get_item.return_value = {
        "Item": {
            "id": "foo",
            "title": "Foo",
            "description": "Hi",
        }
    }
    with fastapi_dep(file_3.app).override(
        {
            AppConfig: lambda: my_mock,
        }
    ):
        response = client.get("/objects/1234")
        assert response.status_code == 200
        assert response.json() == {
            "id": "foo",
            "title": "Foo",
            "description": "Hi",
        }

Другие вопросы по теме