Skip to content

Commit 1ed88d6

Browse files
committed
test: 🚨 Add some FastAPI tests
1 parent b6e1f0b commit 1ed88d6

File tree

4 files changed

+83
-0
lines changed

4 files changed

+83
-0
lines changed

‎pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ flake8-debugger = "^4.1.2"
3030
pytest-cov = ">=3,<5"
3131
tox = ">=3.26,<5.0"
3232
pytest-asyncio = "^0.21.1"
33+
httpx = "^0.24.1"
3334

3435
[tool.isort]
3536
multi_line_output = 3

‎tests/test_fastapi.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import pydantic
2+
import pytest
3+
4+
from pydantic_async_validation import AsyncValidationModelMixin, async_field_validator
5+
6+
try:
7+
import fastapi
8+
from fastapi.testclient import TestClient
9+
10+
from pydantic_async_validation.fastapi import ensure_request_validation_errors
11+
except ImportError:
12+
fastapi = None
13+
14+
15+
class SomethingModel(AsyncValidationModelMixin, pydantic.BaseModel):
16+
name: str
17+
18+
@async_field_validator('name')
19+
async def validate_name(self, value: str) -> None:
20+
if value == "invalid":
21+
raise ValueError("Invalid name")
22+
23+
24+
@pytest.fixture
25+
def app():
26+
app = fastapi.FastAPI()
27+
28+
@app.get("/no-errors")
29+
async def all_valid():
30+
instance = SomethingModel(name="valid")
31+
with ensure_request_validation_errors():
32+
await instance.model_async_validate()
33+
34+
@app.get("/without-request-validation-errors")
35+
async def without():
36+
instance = SomethingModel(name="invalid")
37+
await instance.model_async_validate()
38+
39+
@app.get("/with-request-validation-errors")
40+
async def with_context_manager():
41+
instance = SomethingModel(name="invalid")
42+
with ensure_request_validation_errors():
43+
await instance.model_async_validate()
44+
45+
@app.get("/with-request-validation-errors-decorator")
46+
@ensure_request_validation_errors
47+
async def with_decorator():
48+
instance = SomethingModel(name="invalid")
49+
await instance.model_async_validate()
50+
51+
return app
52+
53+
54+
@pytest.mark.skipif(fastapi is None, reason="fastapi not installed")
55+
def test_fastapi_without_error_just_works(app):
56+
with TestClient(app) as client:
57+
response = client.get("/no-errors")
58+
assert response.status_code == 200
59+
60+
61+
@pytest.mark.skipif(fastapi is None, reason="fastapi not installed")
62+
def test_fastapi_fails_without_handling(app):
63+
with TestClient(app) as client:
64+
with pytest.raises(pydantic.ValidationError):
65+
client.get("/without-request-validation-errors")
66+
67+
68+
@pytest.mark.skipif(fastapi is None, reason="fastapi not installed")
69+
def test_fastapi_triggers_validation_response(app):
70+
with TestClient(app) as client:
71+
response = client.get("/with-request-validation-errors")
72+
assert response.status_code == 422
73+
74+
75+
@pytest.mark.skipif(fastapi is None, reason="fastapi not installed")
76+
def test_fastapi_triggers_validation_response_by_decorator(app):
77+
with TestClient(app) as client:
78+
response = client.get("/with-request-validation-errors-decorator")
79+
assert response.status_code == 422

‎tests/test_field_validators.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ class SomethingModel(AsyncValidationModelMixin, pydantic.BaseModel):
1414

1515
@async_field_validator('name')
1616
async def validate_name(self, value: str) -> None:
17+
assert value == self.name
18+
1719
if value == "invalid":
1820
raise ValueError("Invalid name")
1921

‎tox.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ deps =
1010
pytest
1111
pytest-asyncio
1212
fastapi
13+
httpx
1314
commands = pytest

0 commit comments

Comments
 (0)