簡體   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