Python 依赖注入与FastAPI问题
我在使用依赖项覆盖时出错 我有以下结构的样本项目(附件): service.pyPython 依赖注入与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
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
...
然后测试就可以工作了,所以我想问题的原因在于依赖项覆盖