Skip to content

Commit bbfb62a

Browse files
committed
feat: Performance tests
1 parent 7ca5cbb commit bbfb62a

4 files changed

Lines changed: 229 additions & 0 deletions

File tree

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ FILE = $(file)
44
test:
55
TEST_FILE=$(FILE) docker-compose up --build --abort-on-container-exit
66

7+
test-benchmark:
8+
docker-compose run tests uv run pytest --benchmark-only
9+
710
test-pypi:
811
uv run pytest -xvrs --color=yes -m pypi tests/test_pypi_readiness.py
912

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ lint = [
2828
]
2929
test = [
3030
"pytest==9.0.1",
31+
"pytest-benchmark>=4.0.0",
3132
"pytest-cov==7.0.0",
3233
"requests==2.32.5",
3334
"pytest-mock>=3.15.1",

tests/test_performance.py

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
"""Performance tests for SQLAlchemy serializer using pytest-benchmark."""
2+
3+
from sqlalchemy_serializer.serializer import serialize_collection
4+
5+
from .models import FlatModel, NestedModel, RecursiveModel
6+
7+
8+
def test_benchmark_flat_model_serialization(benchmark, get_instance):
9+
"""Benchmark serialization of a flat model with standard fields."""
10+
model = get_instance(FlatModel)
11+
12+
def serialize():
13+
return model.to_dict()
14+
15+
result = benchmark(serialize)
16+
assert isinstance(result, dict)
17+
assert "id" in result
18+
19+
20+
def test_benchmark_nested_model_serialization(benchmark, get_instance):
21+
"""Benchmark serialization of a nested model with relationships."""
22+
flat = get_instance(FlatModel)
23+
nested = get_instance(NestedModel, model_id=flat.id)
24+
25+
def serialize():
26+
return nested.to_dict()
27+
28+
result = benchmark(serialize)
29+
assert isinstance(result, dict)
30+
assert "model" in result
31+
32+
33+
def test_benchmark_collection_serialization(benchmark, get_instance):
34+
"""Benchmark serialization of a collection of models."""
35+
models = [get_instance(FlatModel) for _ in range(10)]
36+
37+
def serialize():
38+
return serialize_collection(models, only=("id", "string", "bool"))
39+
40+
result = benchmark(serialize)
41+
assert isinstance(result, list)
42+
assert len(result) == 10
43+
44+
45+
def test_benchmark_serialize_only_rules(benchmark, get_instance):
46+
"""Benchmark serialization with serialize_only rules."""
47+
model = get_instance(FlatModel)
48+
49+
def serialize():
50+
return model.to_dict(only=("id", "string", "datetime", "bool"))
51+
52+
result = benchmark(serialize)
53+
assert isinstance(result, dict)
54+
assert len(result.keys()) == 4
55+
56+
57+
def test_benchmark_serialize_rules(benchmark, get_instance):
58+
"""Benchmark serialization with serialize_rules (greedy mode with additions)."""
59+
model = get_instance(FlatModel)
60+
61+
def serialize():
62+
return model.to_dict(rules=("prop", "list", "dict"))
63+
64+
result = benchmark(serialize)
65+
assert isinstance(result, dict)
66+
assert "prop" in result
67+
assert "list" in result
68+
assert "dict" in result
69+
70+
71+
def test_benchmark_nested_serialize_only_rules(benchmark, get_instance):
72+
"""Benchmark nested model serialization with serialize_only rules."""
73+
flat = get_instance(FlatModel)
74+
nested = get_instance(NestedModel, model_id=flat.id)
75+
76+
def serialize():
77+
return nested.to_dict(only=("id", "model.id", "model.string", "model.bool"))
78+
79+
result = benchmark(serialize)
80+
assert isinstance(result, dict)
81+
assert "model" in result
82+
83+
84+
def test_benchmark_nested_serialize_rules(benchmark, get_instance):
85+
"""Benchmark nested model serialization with serialize_rules."""
86+
flat = get_instance(FlatModel)
87+
nested = get_instance(NestedModel, model_id=flat.id)
88+
89+
def serialize():
90+
return nested.to_dict(rules=("-id", "model.prop", "model.list", "model.dict"))
91+
92+
result = benchmark(serialize)
93+
assert isinstance(result, dict)
94+
assert "model" in result
95+
96+
97+
def test_benchmark_type_serialization_datetime(benchmark, get_instance):
98+
"""Benchmark serialization of models with datetime/date/time fields."""
99+
model = get_instance(FlatModel)
100+
101+
def serialize():
102+
return model.to_dict(only=("date", "datetime", "time"))
103+
104+
result = benchmark(serialize)
105+
assert isinstance(result, dict)
106+
assert "date" in result
107+
assert "datetime" in result
108+
assert "time" in result
109+
110+
111+
def test_benchmark_type_serialization_all_types(benchmark, get_instance):
112+
"""Benchmark serialization of models with all supported types."""
113+
model = get_instance(FlatModel)
114+
115+
def serialize():
116+
return model.to_dict(rules=("money", "prop_with_bytes", "uuid", "list", "dict", "set"))
117+
118+
result = benchmark(serialize)
119+
assert isinstance(result, dict)
120+
assert "money" in result
121+
assert "uuid" in result
122+
123+
124+
def test_benchmark_recursive_model_serialization(benchmark, get_instance):
125+
"""Benchmark serialization of recursive models with depth limit."""
126+
parent = get_instance(RecursiveModel)
127+
child1 = get_instance(RecursiveModel, parent_id=parent.id, name="child1")
128+
_ = get_instance(RecursiveModel, parent_id=parent.id, name="child2")
129+
_ = get_instance(RecursiveModel, parent_id=child1.id, name="grandchild")
130+
131+
def serialize():
132+
return parent.to_dict(rules=("children",), max_serialization_depth=2)
133+
134+
result = benchmark(serialize)
135+
assert isinstance(result, dict)
136+
assert "children" in result
137+
138+
139+
def test_benchmark_large_model_serialization(benchmark, get_instance):
140+
"""Benchmark serialization of model with many fields and nested data."""
141+
model = get_instance(FlatModel)
142+
143+
def serialize():
144+
return model.to_dict(
145+
rules=(
146+
"id",
147+
"string",
148+
"date",
149+
"datetime",
150+
"time",
151+
"bool",
152+
"null",
153+
"uuid",
154+
"prop",
155+
"prop_with_bytes",
156+
"list",
157+
"dict",
158+
"set",
159+
"money",
160+
)
161+
)
162+
163+
result = benchmark(serialize)
164+
assert isinstance(result, dict)
165+
assert len(result.keys()) >= 10
166+
167+
168+
def test_benchmark_auto_serialize_properties(benchmark, get_instance):
169+
"""Benchmark serialization with auto_serialize_properties enabled."""
170+
171+
class AutoPropModel(FlatModel):
172+
auto_serialize_properties = True
173+
174+
model = get_instance(AutoPropModel)
175+
176+
def serialize():
177+
return model.to_dict()
178+
179+
result = benchmark(serialize)
180+
assert isinstance(result, dict)
181+
assert "prop" in result
182+
assert "prop_with_bytes" in result
183+
184+
185+
def test_benchmark_custom_formats(benchmark, get_instance):
186+
"""Benchmark serialization with custom date/datetime/time/decimal formats."""
187+
model = get_instance(FlatModel)
188+
189+
def serialize():
190+
return model.to_dict(
191+
date_format="%Y/%m/%d",
192+
datetime_format="%Y/%m/%d %H:%M:%S",
193+
time_format="%H:%M:%S",
194+
decimal_format="{:.2f}",
195+
rules=("money",),
196+
)
197+
198+
result = benchmark(serialize)
199+
assert isinstance(result, dict)
200+
assert "date" in result
201+
assert "money" in result

uv.lock

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)