FastAPI - 向 TestClient 添加路由前缀

FastAPI - adding route prefix to TestClient

我有一个 FastAPI 应用,其路由前缀为 /api/v1

当我 运行 测试时它抛出 404。我看到这是因为 TestClient 无法在 /ping 找到路由,并且当测试用例中的路由更改为 /api/v1/ping.

时可以正常工作

有没有一种方法可以避免根据前缀更改所有测试函数中的所有路由?这似乎很麻烦,因为有很多测试用例,也因为我不想在我的测试用例中硬编码依赖路由前缀。有没有一种方法可以像在 app 中那样在 TestClient 中配置前缀,并像在 routes.py 中提到的那样简单地提及路由?

routes.py

from fastapi import APIRouter

router = APIRouter()

@router.get("/ping")
async def ping_check():
    return {"msg": "pong"}

main.py

from fastapi import FastAPI
from routes import router

app = FastAPI()
app.include_router(prefix="/api/v1")

在我的测试文件中:

test.py

from main import app
from fastapi.testclient import TestClient

client = TestClient(app)

def test_ping():
    response = client.get("/ping")
    assert response.status_code == 200
    assert response.json() == {"msg": "pong"}

找到解决方法。

TestClient 有一个接受 base_url 的选项,然后 urljoin 使用路由 path 编辑。所以我将路由前缀附加到此 base_url.

source:

url = urljoin(self.base_url, url)

但是,这有一个问题 - urljoin 仅当 base_url/ 结尾且path 不以 / 开头。 This SO answer 解释得很好。

这导致了以下变化:

test.py

from main import app, ROUTE_PREFIX
from fastapi.testclient import TestClient

client = TestClient(app)
client.base_url += ROUTE_PREFIX  # adding prefix
client.base_url = client.base_url.rstrip("/") + "/"  # making sure we have 1 and only 1 `/`

def test_ping():
    response = client.get("ping")  # notice the path no more begins with a `/`
    assert response.status_code == 200
    assert response.json() == {"msg": "pong"}

上面的 work-around(Shod 的)对我有用,但我必须将 APIRouter 对象而不是 FastAPI 对象传递给测试客户端。否则我会收到 404 错误。 下面是它如何为我工作的示例代码。

from fastapi import FastAPI, APIRouter
from fastapi.testclient import TestClient

app = FastAPI()
router = APIRouter(prefix="/sample")

app.include_router(router)

@router.post("/s1")
def read_main():
    return {"msg": "Hello World"}

client = TestClient(router)
client.base_url += "/sample"
client.base_url = client.base_url.rstrip("/") + "/"

def test_main():
    response = client.post("s1")
    assert response.status_code == 200
    assert response.json() == {"msg": "Hello World"}