Python 依赖注入与FastAPI问题

Python 依赖注入与FastAPI问题,python,python-3.x,dependency-injection,fastapi,pydantic,Python,Python 3.x,Dependency Injection,Fastapi,Pydantic,我在使用依赖项覆盖时出错 我有以下结构的样本项目(附件): service.py from pydantic import BaseModel class Service(BaseModel): key: int name: str from service import Service class ServiceHandler: async def get_all(self): return [Service(**x) for x in

我在使用依赖项覆盖时出错

我有以下结构的样本项目(附件):

service.py

from pydantic import BaseModel
class Service(BaseModel):
    key: int
    name: str
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'}]]
from fastapi import Depends
from handler import ServiceHandler

async def get_service_handler(handler=Depends(ServiceHandler)):
    return handler
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:
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 = {}
handler.py

from pydantic import BaseModel
class Service(BaseModel):
    key: int
    name: str
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'}]]
from fastapi import Depends
from handler import ServiceHandler

async def get_service_handler(handler=Depends(ServiceHandler)):
    return handler
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:
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 = {}
factory.py

from pydantic import BaseModel
class Service(BaseModel):
    key: int
    name: str
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'}]]
from fastapi import Depends
from handler import ServiceHandler

async def get_service_handler(handler=Depends(ServiceHandler)):
    return handler
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:
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 = {}
main.py

from pydantic import BaseModel
class Service(BaseModel):
    key: int
    name: str
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'}]]
from fastapi import Depends
from handler import ServiceHandler

async def get_service_handler(handler=Depends(ServiceHandler)):
    return handler
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:
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 = {}
单元测试/test.py

from pydantic import BaseModel
class Service(BaseModel):
    key: int
    name: str
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'}]]
from fastapi import Depends
from handler import ServiceHandler

async def get_service_handler(handler=Depends(ServiceHandler)):
    return handler
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:
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单元\u测试/test.py
我得到了一个异常:
FAILED unit\u tests/test.py::test\u get\u services-TypeError:不是可调用对象

我尝试向handler.py添加call,如下所示

...
class ServiceHandler:
    def __call__(self):
        pass
...
而另一个异常发生了:
FAILED unit\u tests/test.py::test\u get\u services-AttributeError:“NoneType”对象没有属性“get\u all”

毕竟,如果我启动服务器:
hypercorn主应用程序:应用程序--重新加载
http://127.0.0.1:8000/services/
不管怎样,一切都很顺利

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

...
app.dependency_overrides[factory.get_service_handler] = handler
...
然后测试就可以工作了,所以我想问题的原因在于依赖项覆盖