python - FastAPI问题的依赖注入(inject)

标签 python python-3.x dependency-injection fastapi pydantic

我在使用 dependency_overrides 时遇到错误 https://fastapi.tiangolo.com/advanced/testing-dependencies/

我有具有以下结构的示例项目(在附件中):

服务.py

from pydantic import BaseModel
class Service(BaseModel):
    key: int
    name: str

处理程序.py

from service import Service

class ServiceHandler:
    async def get_all(self):
        return [Service(**x) for x in
                [{'key': 1, 'name': 'One'},
                 {'key': 2, 'name': 'Two'}]]

工厂.py

from fastapi import Depends
from handler import ServiceHandler

async def get_service_handler(handler=Depends(ServiceHandler)):
    return handler

主.py

from fastapi import FastAPI, APIRouter, Depends
import factory

router = APIRouter()
@router.get("/services/", tags=["services"])
async def get_services(handler=Depends(factory.get_service_handler)):
    return await handler.get_all()

app = FastAPI()
app.include_router(router)

and pytest+pytest-mock unit test for route:

unit_tests/test.py

import...
@pytest.fixture(scope="session", autouse=True)
def client():
    return TestClient(app)

def test_get_services(client, mocker):
    handler = ServiceHandler()
    mocker.patch.object(handler, 'get_all')
    handler.get_all.return_value = [Service(_id=None, key=1, name='Test')]
    app.dependency_overrides[factory.get_service_handler] = handler

    response = client.get("/services")

    assert response.status_code == 200
    # expected = [{'_id': None, 'key': 1, 'name': 'Test'}]
    expected = [{'_id': None, 'key': 1, 'name': 'One'}, {'_id': None, 'key': 2, 'name': 'Two'}]
    assert response.json() == expected

    app.dependency_overrides = {}

当我运行它时: pytest unit_tests/test.py 我遇到了一个异常: FAILED unit_tests/test.py::test_get_services - TypeError: <handler.ServiceHandler object at 0x7fd03d813b50> is not a callable object

我尝试如下添加调用到handler.py

...
class ServiceHandler:
    def __call__(self):
        pass
...

并且另一个异常发生了: FAILED unit_tests/test.py::test_get_services - AttributeError: 'NoneType' object has no attribute 'get_all'

毕竟,如果我启动服务器: hypercorn main:app --reload http://127.0.0.1:8000/services/ 一切都以任何方式运作良好。

如果我注释掉 test.py 中的行:

...
app.dependency_overrides[factory.get_service_handler] = handler
...

然后测试就可以了,所以我猜问题的原因在dependency_overrides。

depends_demo.zip

最佳答案

请替换你的unit_tests/test.py的内容:

from fastapi.testclient import TestClient
from handler import ServiceHandler
import factory
from service import Service
import pytest
from main import app
import asyncio
from unittest.mock import AsyncMock
    


@pytest.fixture(scope="session", autouse=True)
def client():
    return TestClient(app)

def test_get_services(client, mocker):
    handler = ServiceHandler()

    async_mock = AsyncMock(return_value=[Service(_id=None, key=1, name='Test')])
    mocker.patch('handler.ServiceHandler.get_all', side_effect=async_mock)
    app.dependency_overrides[factory.get_service_handler()] = handler

    response = client.get("/services")

    assert response.status_code == 200
    # expected = [{'_id': None, 'key': 1, 'name': 'Test'}]
    expected = [{'_id': None, 'key': 1, 'name': 'One'}, {'_id': None, 'key': 2, 'name': 'Two'}]
    assert response.json() == expected

    app.dependency_overrides = {}

解决问题的两件事:

  • 您需要调用 get_service_handler 来获取处理程序:

app.dependency_overrides[factory.get_service_handler()] = handler

async_mock = AsyncMock(return_value=[Service(_id=None, key=1, name='Test')])
mocker.patch('handler.ServiceHandler.get_all', side_effect=async_mock)

现在我用 pytest unit_tests/test.py -v 运行测试,这是我得到的:

E       AssertionError: assert [{'key': 1, 'name': 'Test'}] == [{'_id': None...name': 'Two'}]
E         At index 0 diff: {'key': 1, 'name': 'Test'} != {'_id': None, 'key': 1, 'name': 'One'}
E         Right contains one more item: {'_id': None, 'key': 2, 'name': 'Two'}
E         Full diff:
E         - [{'_id': None, 'key': 1, 'name': 'One'}, {'_id': None, 'key': 2, 'name': 'Two'}]
E         + [{'key': 1, 'name': 'Test'}]

关于python - FastAPI问题的依赖注入(inject),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64551295/

相关文章:

python - Numpy:用同一行中其他元素的最大值替换一行中的每个元素

python - 如何将列表python计算成矩阵相似度

Python:字符串反转中途停止

python - Pandas Dataframe 保留日期在两个日期之间的行(单独的列)

java - Simple Injector 中是否有相当于 Guice Providers 的东西?

java - 同一 session 中 Sessionscoped Bean 的多个实例

python - 使用 pandas.to_datetime 时只保留日期部分

python - 从 CSV 文件创建图形并使用 Django 和 Pandas Python 库呈现到浏览器

Python:与 urljoin 混淆

javascript - 没有特定 ng-app 模块集的 AngularJS 页面上的自定义指令