test: create pytest conftest with shared fixtures for backend tests

This commit is contained in:
2026-04-18 16:48:30 +00:00
parent cd1dd8ddff
commit be83262644
2 changed files with 156 additions and 25 deletions

View File

@@ -15,4 +15,5 @@ slowapi>=0.1.9
apscheduler>=3.10.1
pytest>=8.0.0
pytest-asyncio>=0.23.0
pytest-cov>=4.1.0
httpx>=0.27.0

View File

@@ -1,14 +1,17 @@
import pytest
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import StaticPool
from fastapi.testclient import TestClient
from unittest.mock import patch, MagicMock
from datetime import datetime, timezone
from backend.database import Base, get_db
from backend.main import app
from backend.database import Base, get_db
from backend.models import User
from backend.config_manager import ConfigManager
from backend.auth import get_current_admin, TokenData
from datetime import datetime, timezone
# Use in-memory SQLite for tests
SQLALCHEMY_DATABASE_URL = "sqlite://"
@@ -20,8 +23,10 @@ engine = create_engine(
)
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
@pytest.fixture(scope="function", autouse=True)
def mock_scheduler():
"""Shutdown scheduler before and after each test to avoid conflicts."""
from backend.scheduler import scheduler
if scheduler.running:
scheduler.shutdown()
@@ -29,37 +34,162 @@ def mock_scheduler():
if scheduler.running:
scheduler.shutdown()
@pytest.fixture(scope="function")
def db():
def test_db():
"""Create in-memory SQLite database for tests."""
Base.metadata.create_all(bind=engine)
session = TestingSessionLocal()
try:
yield session
finally:
session.close()
Base.metadata.drop_all(bind=engine)
@pytest.fixture(scope="function")
def client(db):
def test_client(test_db):
"""Create FastAPI test client with mocked database."""
def override_get_db():
try:
yield db
yield test_db
finally:
pass
# Mock admin user with valid TokenData
def override_get_current_admin():
app.dependency_overrides[get_db] = override_get_db
client = TestClient(app)
yield client
app.dependency_overrides.clear()
@pytest.fixture(scope="function")
def mock_ldap():
"""Mock LDAP authentication."""
with patch("backend.auth.ldap3.Server") as mock_server, \
patch("backend.auth.ldap3.Connection") as mock_conn_class:
mock_conn = MagicMock()
mock_conn.bind.return_value = True
mock_conn.search.return_value = True
mock_conn.entries = [
MagicMock(entry_dn="uid=testuser,ou=people,dc=example,dc=com",
uid=["testuser"])
]
mock_conn_class.return_value = mock_conn
yield mock_conn
@pytest.fixture(scope="function")
def mock_gemini():
"""Mock Google Gemini AI extraction."""
with patch("backend.ai.gemini_extractor.generate_content") as mock_gen:
mock_response = MagicMock()
mock_response.text = '''{
"name": "Test Item",
"part_number": "PN-12345",
"category": "Electronics",
"quantity": 5
}'''
mock_gen.return_value = mock_response
yield mock_gen
@pytest.fixture(scope="function")
def mock_claude():
"""Mock Anthropic Claude AI extraction."""
with patch("backend.ai.claude_extractor.generate_content") as mock_gen:
mock_content = MagicMock()
mock_content.text = '''{
"name": "Test Item",
"part_number": "PN-12345",
"category": "Electronics",
"quantity": 5
}'''
mock_response = MagicMock()
mock_response.content = [mock_content]
mock_gen.return_value = mock_response
yield mock_gen
@pytest.fixture(scope="function")
def mock_config():
"""Mock ConfigManager."""
with patch.object(ConfigManager, "get_config") as mock_get:
mock_get.return_value = {
"ai_provider": "gemini",
"api_key": "test-key"
}
yield mock_get
@pytest.fixture(scope="function")
def admin_token(test_db):
"""Create a test admin user and return auth token."""
admin = User(
username="admin",
hashed_password="hashed_password",
role="admin",
origin="local"
)
test_db.add(admin)
test_db.commit()
test_db.refresh(admin)
# Return mocked admin token data
return TokenData(
sub=1,
sub=admin.id,
username="admin",
role="admin",
exp=datetime.now(timezone.utc)
)
app.dependency_overrides[get_db] = override_get_db
@pytest.fixture(scope="function")
def user_token(test_db):
"""Create a test regular user and return auth token."""
user = User(
username="user",
hashed_password="hashed_password",
role="user",
origin="local"
)
test_db.add(user)
test_db.commit()
test_db.refresh(user)
# Return mocked user token data
return TokenData(
sub=user.id,
username="user",
role="user",
exp=datetime.now(timezone.utc)
)
@pytest.fixture(scope="function")
def admin_client(test_client, admin_token):
"""Create a test client authenticated as admin."""
def override_get_current_admin():
return admin_token
app.dependency_overrides[get_current_admin] = override_get_current_admin
with TestClient(app) as c:
yield c
yield test_client
app.dependency_overrides.clear()
app.dependency_overrides.pop(get_current_admin, None)
@pytest.fixture(scope="function")
def user_client(test_client, user_token):
"""Create a test client authenticated as regular user."""
from backend.auth import get_current_user
def override_get_current_user():
return user_token
app.dependency_overrides[get_current_user] = override_get_current_user
yield test_client
app.dependency_overrides.pop(get_current_user, None)