feat: restructure test infrastructure with unit/integration/system separation
Test Organization: - Create tests/unit/, tests/integration/, tests/system/ directories - Move existing tests into appropriate categories - Add pytest markers (@pytest.mark.unit, @pytest.mark.integration) Shared Fixtures: - Create conftest.py with SQLite engine (for unit tests) - Add PostgreSQL session fixture with transaction rollback - Add TestClient fixture for API tests Configuration: - Update pyproject.toml with asyncio_mode=auto - Add test markers and default addopts - Add aiosqlite dependency for SQLite support E2E Testing: - Initialize Playwright in e2e/ directory - Add playwright.config.ts - Create login flow E2E test Build: - Add test-unit, test-integration, test-system, test-e2e to Makefile - Update test target to run all categories - Add testing documentation to README Note: Some tests have import issues due to missing python-jose package in dev environment. This needs to be addressed separately.
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
"""Shared test fixtures for all test categories."""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from typing import AsyncGenerator, Generator
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
from fastapi.testclient import TestClient
|
||||
from sqlalchemy import create_engine, text
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
from src.config import Settings, build_database_url
|
||||
from src.models.base import Base
|
||||
from src.main import app
|
||||
|
||||
|
||||
# Unit test fixtures (SQLite in-memory)
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def sqlite_engine():
|
||||
"""Create a SQLite in-memory engine for unit tests."""
|
||||
engine = create_engine("sqlite:///:memory:", connect_args={"check_same_thread": False})
|
||||
Base.metadata.create_all(engine)
|
||||
yield engine
|
||||
engine.dispose()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sqlite_session(sqlite_engine) -> Generator:
|
||||
"""Provide a SQLite session for unit tests."""
|
||||
connection = sqlite_engine.connect()
|
||||
transaction = connection.begin()
|
||||
session = sessionmaker(bind=connection)()
|
||||
|
||||
yield session
|
||||
|
||||
session.close()
|
||||
transaction.rollback()
|
||||
connection.close()
|
||||
|
||||
|
||||
# Integration test fixtures (PostgreSQL)
|
||||
|
||||
TEST_DATABASE_URL = build_database_url(
|
||||
user="headquarter",
|
||||
password="headquarter",
|
||||
host="localhost",
|
||||
port=5432,
|
||||
database="headquarter",
|
||||
)
|
||||
|
||||
|
||||
@pytest_asyncio.fixture(scope="session")
|
||||
async def postgres_engine():
|
||||
"""Create a PostgreSQL engine for integration tests."""
|
||||
engine = create_async_engine(TEST_DATABASE_URL)
|
||||
async with engine.begin() as conn:
|
||||
await conn.run_sync(Base.metadata.create_all)
|
||||
yield engine
|
||||
await engine.dispose()
|
||||
|
||||
|
||||
@pytest_asyncio.fixture
|
||||
async def db_session(postgres_engine) -> AsyncGenerator[AsyncSession, None]:
|
||||
"""Provide a database session with transaction rollback."""
|
||||
async with postgres_engine.connect() as connection:
|
||||
transaction = await connection.begin_nested()
|
||||
session_factory = async_sessionmaker(
|
||||
connection, expire_on_commit=False, class_=AsyncSession
|
||||
)
|
||||
session = session_factory()
|
||||
|
||||
yield session
|
||||
|
||||
await session.close()
|
||||
await transaction.rollback()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_client() -> Generator[TestClient, None, None]:
|
||||
"""Provide a FastAPI test client."""
|
||||
with TestClient(app) as client:
|
||||
yield client
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def configure_test_env(monkeypatch):
|
||||
"""Configure environment for testing."""
|
||||
monkeypatch.setenv("DATABASE_URL", TEST_DATABASE_URL)
|
||||
monkeypatch.setenv("APP_ENV", "testing")
|
||||
Reference in New Issue
Block a user