188 lines
5.7 KiB
Python
188 lines
5.7 KiB
Python
"""
|
|
Updated test configuration for Job Forge that matches the actual project structure
|
|
"""
|
|
import pytest
|
|
import asyncio
|
|
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
|
from sqlalchemy.orm import sessionmaker
|
|
from fastapi.testclient import TestClient
|
|
from httpx import AsyncClient
|
|
import os
|
|
from typing import AsyncGenerator
|
|
from unittest.mock import AsyncMock, Mock
|
|
import uuid
|
|
|
|
# Fix import paths to match actual structure
|
|
from src.backend.main import app
|
|
from src.backend.core.database import get_db, Base
|
|
from src.backend.models.user import User
|
|
from src.backend.api.auth import create_access_token, hash_password
|
|
|
|
# Test database URL (use a separate test database)
|
|
TEST_DATABASE_URL = os.getenv(
|
|
"TEST_DATABASE_URL",
|
|
"postgresql+asyncpg://jobforge_user:jobforge_password@localhost:5432/jobforge_test"
|
|
)
|
|
|
|
# Test engine
|
|
test_engine = create_async_engine(TEST_DATABASE_URL, echo=False)
|
|
TestSessionLocal = sessionmaker(test_engine, class_=AsyncSession, expire_on_commit=False)
|
|
|
|
@pytest.fixture(scope="session")
|
|
def event_loop():
|
|
"""Create an instance of the default event loop for the test session."""
|
|
loop = asyncio.get_event_loop_policy().new_event_loop()
|
|
yield loop
|
|
loop.close()
|
|
|
|
@pytest.fixture(scope="session")
|
|
async def setup_test_db():
|
|
"""Set up test database tables."""
|
|
# Create all tables
|
|
async with test_engine.begin() as conn:
|
|
await conn.run_sync(Base.metadata.drop_all)
|
|
await conn.run_sync(Base.metadata.create_all)
|
|
|
|
yield
|
|
|
|
# Cleanup
|
|
async with test_engine.begin() as conn:
|
|
await conn.run_sync(Base.metadata.drop_all)
|
|
|
|
@pytest.fixture
|
|
async def test_db(setup_test_db) -> AsyncGenerator[AsyncSession, None]:
|
|
"""Create a test database session."""
|
|
async with TestSessionLocal() as session:
|
|
try:
|
|
yield session
|
|
finally:
|
|
await session.rollback()
|
|
|
|
@pytest.fixture
|
|
def override_get_db(test_db: AsyncSession):
|
|
"""Override the get_db dependency for testing."""
|
|
def _override_get_db():
|
|
return test_db
|
|
|
|
app.dependency_overrides[get_db] = _override_get_db
|
|
yield
|
|
app.dependency_overrides.clear()
|
|
|
|
@pytest.fixture
|
|
def test_client(override_get_db):
|
|
"""Create a test client."""
|
|
with TestClient(app) as client:
|
|
yield client
|
|
|
|
@pytest.fixture
|
|
async def async_client(override_get_db):
|
|
"""Create an async test client."""
|
|
async with AsyncClient(app=app, base_url="http://test") as client:
|
|
yield client
|
|
|
|
@pytest.fixture
|
|
async def test_user(test_db: AsyncSession):
|
|
"""Create a test user."""
|
|
user = User(
|
|
email="test@jobforge.com",
|
|
password_hash=hash_password("testpassword123"),
|
|
full_name="Test User"
|
|
)
|
|
|
|
test_db.add(user)
|
|
await test_db.commit()
|
|
await test_db.refresh(user)
|
|
return user
|
|
|
|
@pytest.fixture
|
|
def test_user_token(test_user):
|
|
"""Create a JWT token for test user."""
|
|
token_data = {"sub": str(test_user.id)}
|
|
return create_access_token(data=token_data)
|
|
|
|
@pytest.fixture
|
|
def mock_ai_service():
|
|
"""Mock AI service for testing."""
|
|
mock = Mock()
|
|
mock.generate_cover_letter = AsyncMock(return_value={
|
|
"content": "Dear Hiring Manager,\n\nI am writing to express my interest...\n\nBest regards,\nTest User",
|
|
"model_used": "mock-ai",
|
|
"prompt": "Mock prompt for testing"
|
|
})
|
|
mock.generate_resume_optimization = AsyncMock(return_value={
|
|
"content": "Optimized Resume\n\nTest User\nSoftware Engineer\n\nExperience optimized for target role...",
|
|
"model_used": "mock-ai",
|
|
"prompt": "Mock resume optimization prompt"
|
|
})
|
|
return mock
|
|
|
|
@pytest.fixture
|
|
async def multiple_test_users(test_db: AsyncSession):
|
|
"""Create multiple test users for testing."""
|
|
users = []
|
|
for i in range(3):
|
|
user = User(
|
|
email=f"user{i}@test.com",
|
|
password_hash=hash_password("password123"),
|
|
full_name=f"User {i} Test"
|
|
)
|
|
test_db.add(user)
|
|
users.append(user)
|
|
|
|
await test_db.commit()
|
|
for user in users:
|
|
await test_db.refresh(user)
|
|
return users
|
|
|
|
# Test data factories
|
|
class TestDataFactory:
|
|
"""Factory for creating test data."""
|
|
|
|
@staticmethod
|
|
def user_data(email: str = None, **kwargs):
|
|
"""Create user test data."""
|
|
return {
|
|
"email": email or "test@example.com",
|
|
"password": "testpassword123",
|
|
"first_name": "Test",
|
|
"last_name": "User",
|
|
**kwargs
|
|
}
|
|
|
|
@staticmethod
|
|
def cover_letter_request(**kwargs):
|
|
"""Create cover letter request data."""
|
|
return {
|
|
"job_description": "We are looking for a Software Engineer with Python experience",
|
|
"company_name": "Test Company",
|
|
"role_title": "Software Engineer",
|
|
**kwargs
|
|
}
|
|
|
|
@staticmethod
|
|
def resume_optimization_request(**kwargs):
|
|
"""Create resume optimization request data."""
|
|
return {
|
|
"current_resume": "John Doe\nSoftware Engineer\n\nExperience:\n- Python development\n- Web applications",
|
|
"job_description": "Senior Python Developer role requiring FastAPI experience",
|
|
"role_title": "Senior Python Developer",
|
|
**kwargs
|
|
}
|
|
|
|
# Helper functions
|
|
async def create_test_user_and_token(db: AsyncSession, email: str):
|
|
"""Helper to create a user and return auth token."""
|
|
user = User(
|
|
email=email,
|
|
password_hash=hash_password("password123"),
|
|
full_name="Test User"
|
|
)
|
|
|
|
db.add(user)
|
|
await db.commit()
|
|
await db.refresh(user)
|
|
|
|
token_data = {"sub": str(user.id)}
|
|
token = create_access_token(data=token_data)
|
|
|
|
return user, token |