perf: reuse the test schema instead of rebuilding it per test

The autouse _setup_db fixture ran create_all + drop_all for every test in
the suite, including the many that never open a session. That cycle costs
~49ms against these 22 tables; truncating them instead costs ~6ms for the
same guarantee of an empty database per test.

Build the schema once, then delete every row before each subsequent test.
No model sets sqlite_autoincrement, so SQLite reuses rowids after a full
delete and generated ids still restart at 1.

Measured over 874 tests, deterministic order: 138.6s -> 74.5s (~46%).
Verified green under pytest-randomly's default random ordering as well.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-04 10:11:20 +02:00
co-authored by Claude Opus 5
parent f49b422095
commit 70157ccfc2
+21 -4
View File
@@ -15,6 +15,8 @@ from sqlalchemy.ext.asyncio import (
create_async_engine,
)
from sqlalchemy import delete
from app.database import Base
from app.providers.protocol import OHLCVData
@@ -32,14 +34,29 @@ _test_session_factory = async_sessionmaker(
)
_schema_created = False
@pytest.fixture(autouse=True)
async def _setup_db():
"""Create all tables before each test and drop them after."""
"""Hand every test an empty database.
The schema is built once and then truncated per test rather than dropped and
recreated. A create_all/drop_all cycle costs ~49ms against these 22 tables and
ran for every test in the suite — including the many that never open a session
— where deleting every row costs ~6ms for the same guarantee. No model sets
``sqlite_autoincrement``, so SQLite reuses rowids after a full delete and
generated ids still restart at 1.
"""
global _schema_created
async with _test_engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
if not _schema_created:
await conn.run_sync(Base.metadata.create_all)
_schema_created = True
else:
for table in reversed(Base.metadata.sorted_tables):
await conn.execute(delete(table))
yield
async with _test_engine.begin() as conn:
await conn.run_sync(Base.metadata.drop_all)
@pytest.fixture