ai-talent-finder-backend / tests /test_matching_predict.py
ilyass yani
Deploiement backend dans HF Spaces
9df97a2
Raw
History Blame
3.6 kB
import json
import os
import asyncio
from pathlib import Path
from types import SimpleNamespace
from datetime import datetime
from unittest.mock import patch
import numpy as np
TEST_DB_PATH = Path(__file__).resolve().parent / "test_matching_predict.sqlite3"
os.environ.setdefault("DATABASE_URL", f"sqlite:///{TEST_DB_PATH}")
from app.main import app
from app.core.dependencies import get_current_user, get_db
from app.api import matching as matching_module
from app.models.models import JobCriteria, CriteriaSkill, Candidate
class DictNamespace(dict):
"""Helper class that allows both dict-style (.get) and attribute access."""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.__dict__.update(kwargs)
def __getattr__(self, name):
return self.get(name)
def __setattr__(self, name, value):
if name.startswith('_'):
super().__setattr__(name, value)
else:
self[name] = value
class FakeQuery:
def __init__(self, rows):
self.rows = list(rows)
def filter(self, *args, **kwargs):
return self
def order_by(self, *args, **kwargs):
return self
def all(self):
return list(self.rows)
def first(self):
return self.rows[0] if self.rows else None
class FakeSession:
def __init__(self):
self.criteria = SimpleNamespace(
id=1,
recruiter_id=1,
title="Senior Python Developer",
description="Build APIs with FastAPI and SQL",
created_at=datetime.utcnow(),
)
self.criteria_skills = [
DictNamespace(id=1, criteria_id=1, weight=90, skill=SimpleNamespace(name="Python"), name="Python"),
DictNamespace(id=2, criteria_id=1, weight=80, skill=SimpleNamespace(name="SQL"), name="SQL"),
]
self.candidate = SimpleNamespace(
id=10,
full_name="Jean Dupont",
email="jean@example.com",
created_at=datetime.utcnow(),
extracted_job_titles=json.dumps(["Backend Developer"]),
extracted_companies=json.dumps(["ACME"]),
candidate_skills=[
SimpleNamespace(skill=SimpleNamespace(name="Python")),
SimpleNamespace(skill=SimpleNamespace(name="SQL")),
],
)
def query(self, model):
if model is JobCriteria:
return FakeQuery([self.criteria])
if model is CriteriaSkill:
return FakeQuery(self.criteria_skills)
if model is Candidate:
return FakeQuery([self.candidate])
return FakeQuery([])
class FakeModel:
def predict_proba(self, X):
return np.array([[0.12, 0.88]])
class FakeMeta:
def __init__(self):
self.tf = SimpleNamespace(transform=lambda texts: texts)
self.svd = SimpleNamespace(transform=lambda x: x)
def test_predict_for_criteria_returns_ranked_candidates():
fake_session = FakeSession()
with patch("app.api.matching._load_baseline_model", return_value={"model": FakeModel(), "meta": {"tf": FakeMeta().tf, "svd": FakeMeta().svd}}):
with patch("app.api.matching._build_pair_features_single", return_value=np.array([[1.0]])):
data = asyncio.run(matching_module.predict_for_criteria(1, top_k=5, db=fake_session))
assert data["criteria_id"] == 1
assert data["model"] == "baseline"
assert data["top_k"] == 5
assert len(data["results"]) == 1
assert data["results"][0]["candidate_id"] == 10
assert data["results"][0]["predicted_score"] == 88.0