[英]How to avoid authentication dependencies in FastAPI during testing
這可能是一個新手問題,但我無法讓dependency_overrides
用於測試。
按照文檔,這應該很容易實現,但我遺漏了一些東西......
考慮以下代碼:
在 main.py 中:
from fastapi import FastAPI
from routes import router
app = FastAPI()
app.include_router(router)
在 routes.py 中:
from fastapi import APIRouter, status
from fastapi.param_functions import Depends
from fastapi.responses import JSONResponse
from authentication import Authentication
router = APIRouter()
@router.get("/list/", dependencies=[Depends(Authentication(role=user))])
async def return_all():
response = JSONResponse(
status_code=status.HTTP_200_OK,
content="Here is all the objects!"
)
return response
在 test_list.py 中:
from unittest import TestCase
from fastapi.testclient import TestClient
from main import app
from authentication import Authentication
def override_dependencies():
return {"Some": "Thing"}
client = TestClient(app)
app.dependency_overrides[Authentication] = override_dependencies
class ListTestCase(TestCase):
def test_list_get(self):
response = client.get("/list/")
self.assertEqual(200, response.status_code)
給出以下錯誤:
self.assertEqual(200, response.status_code)
AssertionError: 200 != 403
即,它試圖進行身份驗證但被拒絕。 因此,它似乎並沒有覆蓋我的依賴。
請注意,路徑操作裝飾器( @router.get
)中使用了 Depends,而不是文檔中的函數……
我看到您正在使用Authentication(role=user)
作為依賴項,但隨后您嘗試覆蓋Authentication
,這是兩個不同的可調用對象,前者實際上是Authentication(role=user).__call__
; 因此我猜 FastAPI 無法匹配正確的覆蓋。
這種方法的問題是Authentication(role=user).__call__
是一個實例方法,但是為了覆蓋 dependency_overrides 中的dependency_overrides
項,您必須能夠靜態地處理可調用對象,以便每次調用時它總是相同的它。
我必須實現一個類似的東西,我通過像這樣注入身份驗證邏輯來解決這個問題:
class RestIdentityValidator:
methods: List[AuthMethod]
def __init__(self, *methods: AuthMethod):
self.methods = list(dict.fromkeys([e for e in AuthMethod] if methods is None else methods))
def __call__(
self,
bearer_token_identity: IdentityInfo | None = Depends(get_bearer_token_identity),
basic_token_identity: IdentityInfo | None = Depends(get_basic_token_identity)
) -> IdentityInfo | None:
identity = None
for auth_method in self.methods:
match auth_method:
case AuthMethod.BEARER:
identity = bearer_token_identity
case AuthMethod.BASIC:
identity = basic_token_identity
case _:
pass
if identity is not None:
break
return identity
然后像這樣使用它:
@router.get("/users", response_model=Response[List[UserOut]])
async def get_all_users(
identity: IdentityInfo = Depends(RestIdentityValidator(AuthMethod.BEARER)),
...
然后你可以正常注入和覆蓋它。 在這種情況下,您在裝飾器中使用它的事實不應該有任何區別。
現在這個示例沒有實現與您相同的功能,但我希望它可以為您提供有關如何解決問題的提示。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.