[英]FastAPI: How to test APIs by overriding functions in `Depends()`
I am very, very new to FastAPI testing, so any guidance in the right direction would be appreciated.我对 FastAPI 测试非常非常陌生,因此我们将不胜感激任何正确方向的指导。
So what I have right now is as follows:所以我现在拥有的如下:
A very simple routes file: datapoint_routes.py一个非常简单的路由文件:datapoint_routes.py
from fastapi import APIRouter, Depends
datapoint_router = APIRouter()
def some_function_is():
return "Actual"
@datapoint_router.get('/{datapoint_name}')
def get_db(
datapoint_name: str,
some_function_output=Depends(some_function_is)
) -> dict:
return {
'datapoint_name': datapoint_name,
'state': some_function_output
}
I want to be able to test this.我希望能够对此进行测试。 I checked out FastAPI Testing Dependencies guide here .我在这里查看了 FastAPI 测试依赖项指南。 But this did not help at all, because it didn't work for me.但这根本没有帮助,因为它对我不起作用。
For my tests, what I have right now is something like this:对于我的测试,我现在拥有的是这样的:
File: test_datapoint_router.py文件:test_datapoint_router.py
from typing import Union
from fastapi import FastAPI
from fastapi.testclient import TestClient
from datapoint_routes import datapoint_router, some_function_is
DATAPOINT_NAME = 'abcdef'
app = FastAPI()
client = TestClient(datapoint_router)
def override_dep(q: Union[str, None] = None):
return "Test"
app.dependency_overrides[some_function_is] = override_dep
def test_read_main():
response = client.get(f"/{DATAPOINT_NAME}")
assert response.status_code == 200
assert response.json() == {
'datapoint_name': DATAPOINT_NAME,
'state': "Test"
}
I would hope in the test, the response = client.get()
would be based on the overriding function override_dep
, which would replace some_function_is
.我希望在测试中, response = client.get()
将基于覆盖函数override_dep
,它将替换some_function_is
。
I thought the response.json()
would be:我认为response.json()
将是:
{
'datapoint_name': 'abcdef',
'state': 'Test'
}
instead, it is:相反,它是:
{
'datapoint_name': 'abcdef',
'state': 'Actual'
}
This means that the override_dep
function in the test is useless.这意味着测试中的override_dep
函数是没有用的。
I even checked out the value of app.dependency_overrides
, and it shows a correct map:我什至检查了app.dependency_overrides
的值,它显示了正确的映射:
(Pdb) app.dependency_overrides
{<function some_function_is at 0x102b3d1b0>: <function override_dep at 0x102b3e0e0>}
Where the memory values of functions do match:函数的内存值匹配的地方:
(Pdb) some_function_is
<function some_function_is at 0x102b3d1b0>
(Pdb) override_dep
<function override_dep at 0x102b3e0e0>
What am I doing wrong?我究竟做错了什么?
You're creating the FastAPI app
object in your test , but you're using a defined router with your TestClient
.您正在test 中创建 FastAPI app
对象,但您正在使用已定义的路由器与您的TestClient
。 Since this router is never registered with the app, overriding a dependency with the app won't do anything useful.由于此路由器从未在应用程序中注册,因此使用应用程序覆盖依赖项不会做任何有用的事情。
The TestClient is usually used with the root app (so that the tests run against the app itself): TestClient 通常与根应用程序一起使用(以便测试针对应用程序本身运行):
from fastapi import APIRouter, Depends, FastAPI
app = FastAPI()
datapoint_router = APIRouter()
def some_function_is():
return "Actual"
@datapoint_router.get('/{datapoint_name}')
def get_db(
datapoint_name: str,
some_function_output=Depends(some_function_is)
) -> dict:
return {
'datapoint_name': datapoint_name,
'state': some_function_output
}
app.include_router(datapoint_router)
And then the test:然后是测试:
from typing import Union
from fastapi.testclient import TestClient
from datapoint_routes import app, datapoint_router, some_function_is
DATAPOINT_NAME = 'abcdef'
client = TestClient(app)
def override_dep(q: Union[str, None] = None):
return "Test"
app.dependency_overrides[some_function_is] = override_dep
def test_read_main():
response = client.get(f"/{DATAPOINT_NAME}")
assert response.status_code == 200
assert response.json() == {
'datapoint_name': DATAPOINT_NAME,
'state': "Test"
}
This passes as expected, since you're now testing against the app ( TestClient(app)
) - the location where you overrode the dependency.这按预期通过了,因为您现在正在针对应用程序( TestClient(app)
)进行测试 - 您覆盖依赖项的位置。
MatsLindh's answer does solve the problem, and I would like to suggest another improvement. MatsLindh 的回答确实解决了这个问题,我想提出另一项改进。
Overriding the depends function at the root of the test file, introduces a risk of interfering with the following tests, due to a lack of cleanup.由于缺乏清理,覆盖测试文件根目录的依赖函数会引入干扰以下测试的风险。
Instead, I suggest using a fixture, which would ensure the isolation of your tests.相反,我建议使用夹具,这将确保您的测试隔离。 I wrote a simple pytest plugin to integrate with the dependency system of FastAPI to simplify the syntax as well.我编写了一个简单的 pytest 插件来与 FastAPI 的依赖系统集成以简化语法。
Install it via: pip install pytest-fastapi-deps
and then use it like so:通过以下方式安装它: pip install pytest-fastapi-deps
然后像这样使用它:
from typing import Union
from fastapi.testclient import TestClient
from datapoint_routes import app, datapoint_router, some_function_is
DATAPOINT_NAME = 'abcdef'
client = TestClient(app)
def override_dep(q: Union[str, None] = None):
return "Test"
def test_read_main_context_manager(fastapi_dep):
with fastapi_dep(app).override({some_function_is: override_dep}):
response = client.get(f"/{DATAPOINT_NAME}")
assert response.status_code == 200
assert response.json() == {
'datapoint_name': DATAPOINT_NAME,
'state': "Test"
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.