2 votes

FastAPI - la fonction "mocking path" n'a pas d'effet

J'ai un simple FastAPI et j'essaie de créer des tests avec pytest pour cela.

Mon objectif est de tester le comportement de l'application en cas d'erreurs diverses.

J'ai un itinéraire simple de contrôle de santé dans mon application :

from fastapi import APIRouter

router = APIRouter()

@router.get("/health")
async def health():
    return "It's working "

Maintenant, dans mon module pytest, j'essaie de corriger la fonction ci-dessus pour qu'elle génère des erreurs différentes. J'utilise unittest.mock mais j'obtiens un comportement très étrange.

import pytest
from unittest import mock

from fastapi import HTTPException
from starlette.testclient import TestClient

import app.api.health
from app.main import app  # this is my application (FastAPI instance) with the `router` attached

@pytest.fixture()
def client():
    with TestClient(app) as test_client:
        yield test_client

def test_simple(client):
    def mock_health_function():
        raise HTTPException(status_code=400, detail='gibberish')

    with mock.patch('app.api.health.health', mock_health_function):
        response = client.get(HEALTHCHECK_PATH)

        with pytest.raises(HTTPException):  # this check passes successfully - my exception is raised
            app.api.health.health()

    assert response.status_code != 200  # this check does not pass. The original function was called as if nothing was patched

Bien que la même fonction soit appelée à l'intérieur du test, le client de test de l'API appelle toujours la fonction d'origine lorsque j'accède au point de terminaison.

Pourquoi les mock.patch ne fonctionne pas correctement lorsque la fonction n'est pas appelée directement dans le test ?

Ou peut-être devrais-je aborder mon problème d'une manière différente ?

0voto

Thomas Points 615

Vous pouvez utiliser monkeypatch pour patcher votre fonction.

Sortez d'abord la section de code que vous souhaitez corriger :

from fastapi import FastAPI

app = FastAPI()

def response():
    return "It's working "

@app.get("/health")
async def health():
    return response()

Utilisez ensuite monkeypatch dans votre test

import pytest

from fastapi import HTTPException
from starlette.testclient import TestClient

from app import main

def mocked_response():
    raise HTTPException(status_code=400, detail='gibberish')

@pytest.fixture()
def client():
    from app.main import app

    with TestClient(app) as test_client:
        yield test_client

def test_simple(client, monkeypatch):

    monkeypatch.setattr(main, "response", mocked_response)
    resp = client.get("/health")
    assert resp.status_code == 400
    assert resp.json()["detail"] == "gibberish"

Une autre approche consisterait à utiliser Dépendances , ainsi que dependencies_overrides . Cela ne fonctionnera probablement pas pour tous les scénarios, mais pour votre cas d'utilisation, c'est le cas.

from fastapi import FastAPI,  Depends

app = FastAPI()

def response():
    return "It's working "

@app.get("/health")
async def health(resp=Depends(response)):
    return resp

Dans votre client de test, vous pouvez maintenant remplacer la dépendance comme suit :

import pytest

from fastapi import HTTPException
from starlette.testclient import TestClient

from app.main import response

def mocked_response():
    raise HTTPException(status_code=400, detail='gibberish')

@pytest.fixture()
def client():
    from app.main import app
    app.dependency_overrides[response] = mocked_response

    with TestClient(app) as test_client:
        yield test_client

def test_simple(client):

    resp = client.get("/health")

    assert resp.status_code == 400
    assert resp.json()["detail"] == "gibberish"

Si vous devez ajouter des arguments à votre fonction de réponse, vous pouvez utiliser le modèle de fermeture

def response_closure():
    def response(arg):
        return arg
    return response

@app.get("/health")
async def health(resp=Depends(response_closure)):
    return resp("It's working ")

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X