我在使用 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。
最佳答案
请替换你的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
- 也许您需要异步函数的异步模拟,所以我在这里阅读了它:https://dino.codes/posts/mocking-asynchronous-functions-python/ .那里说如果你在python3.8以上,应该使用AsyncMock:
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/