简体   繁体   中英

How to test httpError in fastAPI with pytest?

I'm trying make some api server with FastAPI. I have one endpoint named /hello on my project, which gives:

{msg : "Hello World"}

with JSON format when 200 status.

However, It gives error msg when request fails.

Quite simple service. However, I want to test both cases, just for my study. So I also made test code with pytest .

Now I want to know: how can I raise HTTPException and test it on purpose?

#main.py (FAST API)

@app.get('/hello')
def read_main():
    try:
        return {"msg":"Hello World"}
    except requests.exceptions.HTTPError as e:
        raise HTTPException(status_code=400,detail='error occured')

#test.py

from fastapi.testclient import TestClient


client = TestClient(app)


# This test works
def test_read_main():
    response = client.get("/hello")
    assert response.json() == {"msg":"Hello World"}
    assert response.status_code == 200

def test_errors():
    # How can I test except in endpoint "/hello" ?
    # The code below never works as I expect
    # with pytest.raises(HTTPException) as e:
    #    raise client.get("/hello").raise_for_status()
    # print(e.value)

The problem here is that your logic is way to simplistic to test. As luk2302 said; in the current form, your except block is never called and thus can never be tested. Replacing your logic with something more testable, allows us to force an Exception being thrown.

File: app.py

from fastapi import FastAPI
from fastapi.exceptions import HTTPException
import requests

app = FastAPI()

#We've put this in a seperate function so we can mock this.
def get_value():
    return {"msg":"Hello World"}

@app.get('/hello')
def read_main():
    try:
        return get_value()
    except requests.exceptions.HTTPError as e:
        raise HTTPException(status_code=400,detail='error occured')

Note that the return value of your endpoint is now actually provided by the get_value() function.

The test.py file would look like this:

from fastapi import HTTPException
import app
from fastapi.testclient import TestClient
import requests
from pytest_mock import MockerFixture

client = TestClient(app.app)

def test_read_main():
    response = client.get("/hello")
    assert response.json() == {"msg":"Hello World"}
    assert response.status_code == 200

def get_value_raise():
    raise requests.exceptions.HTTPError()

def test_errors(mocker: MockerFixture):
    mocker.patch("app.get_value", get_value_raise)
    response = client.get("/hello")
    assert response.status_code == 400
    assert response.json() == {"detail": "error occured"}

Note that we replace the app.get_value function with a function that will definitely raise the type of exception that you are catching in your application logic. The response of the test client is (however) just an HTTP response, but with statuscode 400 and a detail in the json body. We assert for that.

The result:

(.venv) jarro@MBP-van-Jarro test_http_exception % pytest test.py
=================================================== test session starts ===================================================
platform darwin -- Python 3.10.4, pytest-7.1.2, pluggy-1.0.0
rootdir: /Users/jarro/Development/fastapi-github-issues/SO/test_http_exception
plugins: anyio-3.6.1, mock-3.8.2
collected 2 items                                                                                                         

test.py ..                                                                                                          [100%]

==================================================== 2 passed in 0.17s ====================================================

I used pytest, and by extension I used pytest-mocker to mock the get_value function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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