From 3a6a0a6a2dbedcbe79a20c4072cb5968bc91122d Mon Sep 17 00:00:00 2001 From: Kinuax Date: Sun, 27 Jul 2025 11:57:08 +0200 Subject: [PATCH] Simplify and extend tests --- tests/test_validation_error_fields.py | 140 ++++++++++++++++++++++---- 1 file changed, 123 insertions(+), 17 deletions(-) diff --git a/tests/test_validation_error_fields.py b/tests/test_validation_error_fields.py index efe117ebb..d5a41dff4 100644 --- a/tests/test_validation_error_fields.py +++ b/tests/test_validation_error_fields.py @@ -1,8 +1,9 @@ import pytest from fastapi import APIRouter, FastAPI from fastapi.testclient import TestClient +from pydantic import BaseModel -from .utils import needs_pydanticv2 +from .utils import needs_pydanticv1, needs_pydanticv2 @needs_pydanticv2 @@ -10,38 +11,51 @@ from .utils import needs_pydanticv2 "include_error_input,include_error_url", [(False, False), (False, True), (True, False), (True, True)], ) -def test_input_and_url_fields(include_error_input, include_error_url): +def test_input_and_url_fields_with_pydanticv2(include_error_input, include_error_url): app = FastAPI( include_error_input=include_error_input, include_error_url=include_error_url ) - @app.get("/path1/{path_param}") - def path1(path_param: int): - return {"path_param": path_param} + @app.get("/get1/{path_param}") + def get1(path_param: int): + ... - @app.get("/path2/") - def path2(query_param: int): - return query_param + @app.get("/get2/") + def get2(query_param: int): + ... + + class Body1(BaseModel): + ... + + class Body2(BaseModel): + ... + + @app.post("/post1/") + def post1(body1: Body1, body2: Body2): + ... router = APIRouter( include_error_input=include_error_input, include_error_url=include_error_url ) - @router.get("/path3/{path_param}") - def path3(path_param: int): - return {"path_param": path_param} + @router.get("/get3/{path_param}") + def get3(path_param: int): + ... + + @router.get("/get4/") + def get4(query_param: int): + ... - @router.get("/path4/") - def path4(query_param: int): - return query_param + @router.post("/post2/") + def post2(body1: Body1, body2: Body2): + ... app.include_router(router) client = TestClient(app) - with client: invalid = "not-an-integer" - for path in ["path1", "path3"]: + for path in ["get1", "get3"]: response = client.get(f"/{path}/{invalid}") assert response.status_code == 422, response.text error = response.json()["detail"][0] @@ -54,7 +68,7 @@ def test_input_and_url_fields(include_error_input, include_error_url): else: assert "url" not in error - for path in ["path2", "path4"]: + for path in ["get2", "get4"]: response = client.get(f"/{path}/") assert response.status_code == 422, response.text error = response.json()["detail"][0] @@ -79,3 +93,95 @@ def test_input_and_url_fields(include_error_input, include_error_url): assert "url" in error else: assert "url" not in error + + for path in ["post1", "post2"]: + response = client.post(f"/{path}/", json=["not-a-dict"]) + assert response.status_code == 422 + error = response.json()["detail"][0] + if include_error_input: + assert error["type"] == "missing" + assert error["input"] is None + else: + assert "input" not in error + if include_error_url: + assert "url" in error + else: + assert "url" not in error + + +# TODO: remove when deprecating Pydantic v1 +@needs_pydanticv1 +@pytest.mark.parametrize( + "include_error_input,include_error_url", + [(False, False), (False, True), (True, False), (True, True)], +) +def test_input_and_url_fields_with_pydanticv1(include_error_input, include_error_url): + app = FastAPI( + include_error_input=include_error_input, include_error_url=include_error_url + ) + + @app.get("/get1/{path_param}") + def get1(path_param: int): + ... + + @app.get("/get2/") + def get2(query_param: int): + ... + + class Body1(BaseModel): + ... + + class Body2(BaseModel): + ... + + @app.post("/post1/") + def post1(body1: Body1, body2: Body2): + ... + + router = APIRouter( + include_error_input=include_error_input, include_error_url=include_error_url + ) + + @router.get("/get3/{path_param}") + def get3(path_param: int): + ... + + @router.get("/get4/") + def get4(query_param: int): + ... + + @router.post("/post2/") + def post2(body1: Body1, body2: Body2): + ... + + app.include_router(router) + client = TestClient(app) + with client: + invalid = "not-an-integer" + + for path in ["get1", "get3"]: + response = client.get(f"/{path}/{invalid}") + assert response.status_code == 422, response.text + error = response.json()["detail"][0] + assert "input" not in error + assert "url" not in error + + for path in ["get2", "get4"]: + response = client.get(f"/{path}/") + assert response.status_code == 422, response.text + error = response.json()["detail"][0] + assert "input" not in error + assert "url" not in error + + response = client.get(f"/{path}/?query_param={invalid}") + assert response.status_code == 422, response.text + error = response.json()["detail"][0] + assert "input" not in error + assert "url" not in error + + for path in ["post1", "post2"]: + response = client.post(f"/{path}/", json=["not-a-dict"]) + assert response.status_code == 422 + error = response.json()["detail"][0] + assert "input" not in error + assert "url" not in error