繁体   English   中英

FastAPI:如何通过覆盖 `Depends()` 中的函数来测试 API

[英]FastAPI: How to test APIs by overriding functions in `Depends()`

我对 FastAPI 测试非常非常陌生,因此我们将不胜感激任何正确方向的指导。

所以我现在拥有的如下:

一个非常简单的路由文件: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
    }

我希望能够对此进行测试。 在这里查看了 FastAPI 测试依赖项指南 但这根本没有帮助,因为它对我不起作用。


对于我的测试,我现在拥有的是这样的:

文件: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"
    }

我希望在测试中, response = client.get()将基于覆盖函数override_dep ,它将替换some_function_is

我认为response.json()将是:

{
    'datapoint_name': 'abcdef',
    'state': 'Test'
}

相反,它是:

{
    'datapoint_name': 'abcdef',
    'state': 'Actual'
}

这意味着测试中的override_dep函数是没有用的。

我什至检查了app.dependency_overrides的值,它显示了正确的映射:

(Pdb) app.dependency_overrides
{<function some_function_is at 0x102b3d1b0>: <function override_dep at 0x102b3e0e0>}

函数的内存值匹配的地方:

(Pdb) some_function_is
<function some_function_is at 0x102b3d1b0>

(Pdb) override_dep
<function override_dep at 0x102b3e0e0>

我究竟做错了什么?

您正在test 中创建 FastAPI app对象,但您正在使用已定义的路由器与您的TestClient 由于此路由器从未在应用程序中注册,因此使用应用程序覆盖依赖项不会做任何有用的事情。

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)

然后是测试:

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"
    }

这按预期通过了,因为您现在正在针对应用程序( TestClient(app) )进行测试 - 您覆盖依赖项的位置。

MatsLindh 的回答确实解决了这个问题,我想提出另一项改进。

由于缺乏清理,覆盖测试文件根目录的依赖函数会引入干扰以下测试的风险。

相反,我建议使用夹具,这将确保您的测试隔离。 我编写了一个简单的 pytest 插件来与 FastAPI 的依赖系统集成以简化语法。

通过以下方式安装它: 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM