简体   繁体   English

如何使用 pytest 在 fastAPI 中测试 httpError?

[英]How to test httpError in fastAPI with pytest?

I'm trying make some api server with FastAPI.我正在尝试使用 FastAPI 制作一些 api 服务器。 I have one endpoint named /hello on my project, which gives:我的项目中有一个名为/hello的端点,它提供:

{msg : "Hello World"} {味精:“你好世界”}

with JSON format when 200 status. 200 状态时使用 JSON 格式。

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 .所以我也用pytest做了测试代码。

Now I want to know: how can I raise HTTPException and test it on purpose?现在我想知道:如何引发HTTPException并故意对其进行测试?

#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;正如 luk2302 所说; in the current form, your except block is never called and thus can never be tested.在当前形式中,您的except块永远不会被调用,因此永远不会被测试。 Replacing your logic with something more testable, allows us to force an Exception being thrown.用更可测试的东西替换你的逻辑,允许我们强制抛出异常。

File: app.py文件: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.请注意,您的端点的返回值现在实际上由get_value()函数提供。

The test.py file would look like this: test.py 文件如下所示:

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.请注意,我们将app.get_value函数替换为一个肯定会引发您在应用程序逻辑中捕获的异常类型的函数。 The response of the test client is (however) just an HTTP response, but with statuscode 400 and a detail in the json body.测试客户端的响应(然而)只是一个 HTTP 响应,但状态码为 400 和 json 正文中的详细信息。 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.我使用了 pytest,并且通过扩展我使用了 pytest-mocker 来模拟get_value函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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