在使用python dependency injector框架的更复杂的设置中,我使用FastAPI应用程序对象的lifetime函数来正确连接所有内容。
在测试时,我想用不同的版本(fakes)替换一些对象,在我看来,实现这一点的自然方法是重写或模仿应用对象的lifetime函数。但是我不知道我是否/如何做到这一点。
MRE如下
import pytest
from contextlib import asynccontextmanager
from fastapi.testclient import TestClient
from fastapi import FastAPI, Response, status
greeting = None
@asynccontextmanager
async def _lifespan(app: FastAPI):
# Initialize dependency injection
global greeting
greeting = "Hello"
yield
@asynccontextmanager
async def _lifespan_override(app: FastAPI):
# Initialize dependency injection
global greeting
greeting = "Hi"
yield
app = FastAPI(title="Test", lifespan=_lifespan)
@app.get("/")
async def root():
return Response(status_code=status.HTTP_200_OK, content=greeting)
@pytest.fixture
def fake_client():
with TestClient(app) as client:
yield client
def test_override(fake_client):
response = fake_client.get("/")
assert response.text == "Hi"
因此,基本上在fake_client
fixture中,我想将其更改为使用_lifespan_override
而不是原始的_lifespan
,从而使上面的虚拟测试用例通过
我希望像with TestClient(app, lifespan=_lifespan_override) as client:
这样的东西可以工作,但不支持。有没有什么方法可以让我嘲笑它来得到我想要的行为?
(The如果在assert语句中将“Hi”替换为“Hello”,则上面的mre可以工作)
下面的pyproject.toml以及所需的依赖项
[tool.poetry]
name = "mre"
version = "0.1.0"
description = "mre"
authors = []
[tool.poetry.dependencies]
python = "^3.10"
fastapi = "^0.103.2"
[tool.poetry.group.dev.dependencies]
pytest = "^7.1.2"
httpx = "^0.25.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
编辑:尝试扩展我的代码与建议从哈米德Akhavan如下
@pytest.fixture
def fake_client():
app.dependency_overrides[_lifespan] = _lifespan_override
with TestClient(app) as client:
yield client
但它不起作用,即使它看起来应该是正确的方法。有问题吗?
2条答案
按热度按时间wfsdck301#
根据FastAPI文档,我认为覆盖
lifespan
的正确方法是:6psbrbz92#
我找到了一个解决我的问题的方法,它不包括重写lifetime函数,所以不是上面问题的通用解决方案。
正如我提到的,我在真实的应用程序中的具体问题是使用python依赖注入器框架,它为它的容器提供了重写方法。因此,解决方案是在测试过程中连接依赖项时使用该重写功能,这意味着不需要触及lifetime函数
这里有一个完整的工作MRE的情况下,任何人都感兴趣。