TalentLensAI / test_module.py
Johnny
updated unit tests, and supabase
cc174b7
import pytest
from unittest.mock import patch, MagicMock
from io import BytesIO
# Import all functions to test
from utils import (
extract_keywords,
parse_resume,
extract_email,
score_candidate,
summarize_resume,
filter_resumes_by_keywords,
evaluate_resumes,
store_in_supabase,
generate_pdf_report,
generate_interview_questions_from_summaries
)
# Run Command for Full Coverage Report: pytest --cov=utils --cov-report=term-missing -v
# --- Mock Models and External APIs ---
@pytest.fixture(autouse=True)
def patch_embedding_model(monkeypatch):
mock_model = MagicMock()
mock_model.encode.return_value = [0.1, 0.2, 0.3]
monkeypatch.setattr("utils.embedding_model", mock_model)
@pytest.fixture(autouse=True)
def patch_spacy(monkeypatch):
nlp_mock = MagicMock()
nlp_mock.return_value = [MagicMock(text="python", pos_="NOUN", is_stop=False)]
monkeypatch.setattr("utils.nlp", nlp_mock)
# --- extract_keywords ---
def test_extract_keywords():
text = "We are looking for a Python developer with Django and REST experience."
keywords = extract_keywords(text)
assert isinstance(keywords, list)
assert "python" in keywords or len(keywords) > 0
# --- parse_resume ---
def test_parse_resume():
dummy_pdf = MagicMock()
dummy_pdf.read.return_value = b"%PDF-1.4"
with patch("fitz.open") as mocked_fitz:
page_mock = MagicMock()
page_mock.get_text.return_value = "Resume Text Here"
mocked_fitz.return_value = [page_mock]
result = parse_resume(dummy_pdf)
assert "Resume Text" in result
# --- extract_email ---
def test_extract_email():
text = "Contact me at johndoe@example.com for more info."
assert extract_email(text) == "johndoe@example.com"
assert extract_email("No email here!") is None
# --- score_candidate ---
def test_score_candidate():
score = score_candidate("Experienced Python developer", "Looking for Python engineer")
assert isinstance(score, float)
assert 0 <= score <= 1
# --- summarize_resume ---
@patch("utils.query")
def test_summarize_resume(mock_query):
mock_query.return_value = [{"generated_text": "This is a summary"}]
summary = summarize_resume("This is a long resume text.")
assert summary == "This is a summary"
mock_query.return_value = None
fallback = summarize_resume("Another resume")
assert "unavailable" in fallback.lower()
# --- filter_resumes_by_keywords ---
def test_filter_resumes_by_keywords():
resumes = [
{"name": "John", "resume": "python django rest api"},
{"name": "Doe", "resume": "java spring"}
]
job_description = "Looking for a python developer with API knowledge."
filtered, removed = filter_resumes_by_keywords(resumes, job_description, min_keyword_match=1)
assert isinstance(filtered, list)
assert isinstance(removed, list)
assert len(filtered) + len(removed) == 2
# --- evaluate_resumes ---
@patch("utils.parse_resume", return_value="python flask api")
@patch("utils.extract_email", return_value="test@example.com")
@patch("utils.summarize_resume", return_value="A senior Python developer.")
@patch("utils.score_candidate", return_value=0.85)
def test_evaluate_resumes(_, __, ___, ____):
class DummyFile:
def __init__(self, name): self.name = name
def read(self): return b"%PDF-1.4"
uploaded_files = [DummyFile("resume1.pdf")]
job_desc = "Looking for a python developer."
shortlisted, removed = evaluate_resumes(uploaded_files, job_desc)
assert len(shortlisted) == 1
assert isinstance(removed, list)
# --- store_in_supabase ---
@patch("utils.supabase")
def test_store_in_supabase(mock_supabase):
table_mock = MagicMock()
table_mock.insert.return_value.execute.return_value = {"status": "success"}
mock_supabase.table.return_value = table_mock
response = store_in_supabase("text", 0.8, "John", "john@example.com", "summary")
assert "status" in response
# --- generate_pdf_report ---
def test_generate_pdf_report():
candidates = [{
"name": "John Doe",
"email": "john@example.com",
"score": 0.87,
"summary": "Python developer"
}]
pdf = generate_pdf_report(candidates, questions=["What are your strengths?"])
assert isinstance(pdf, BytesIO)
# --- generate_interview_questions_from_summaries ---
@patch("utils.client.chat_completion")
def test_generate_interview_questions_from_summaries(mock_chat):
mock_chat.return_value.choices = [
MagicMock(message=MagicMock(content="""
1. What are your strengths?
2. Describe a project you've led.
3. How do you handle tight deadlines?
"""))
]
candidates = [{"summary": "Experienced Python developer"}]
questions = generate_interview_questions_from_summaries(candidates)
assert len(questions) > 0
assert all(q.startswith("Q") for q in questions)
@patch("utils.supabase")
def test_store_in_supabase(mock_supabase):
mock_table = MagicMock()
mock_execute = MagicMock()
mock_execute.return_value = {"status": "success"}
# Attach mocks
mock_table.insert.return_value.execute = mock_execute
mock_supabase.table.return_value = mock_table
data = {
"resume_text": "Some text",
"score": 0.85,
"candidate_name": "Alice",
"email": "alice@example.com",
"summary": "Experienced backend developer"
}
response = store_in_supabase(**data)
assert response["status"] == "success"
mock_supabase.table.assert_called_once_with("candidates")
mock_table.insert.assert_called_once()
inserted_data = mock_table.insert.call_args[0][0]
assert inserted_data["name"] == "Alice"
assert inserted_data["email"] == "alice@example.com"
def test_extract_keywords_empty_input():
assert extract_keywords("") == []
def test_extract_email_malformed():
malformed_text = "email at example dot com"
assert extract_email(malformed_text) is None
def test_score_candidate_failure(monkeypatch):
def broken_encode(*args, **kwargs): raise Exception("fail")
monkeypatch.setattr("utils.embedding_model.encode", broken_encode)
score = score_candidate("resume", "job description")
assert score == 0
@patch("utils.query")
def test_summarize_resume_bad_response(mock_query):
mock_query.return_value = {"weird_key": "no summary here"}
summary = summarize_resume("Resume text")
assert "unavailable" in summary.lower()
@patch("utils.query")
def test_summarize_resume_bad_response(mock_query):
mock_query.return_value = {"weird_key": "no summary here"}
summary = summarize_resume("Resume text")
assert "unavailable" in summary.lower()
@patch("utils.parse_resume", return_value="some text")
@patch("utils.extract_email", return_value=None)
@patch("utils.summarize_resume", return_value="Summary here")
@patch("utils.score_candidate", return_value=0.1)
def test_evaluate_resumes_low_score_filtered(_, __, ___, ____):
class Dummy:
name = "resume.pdf"
def read(self): return b"%PDF"
uploaded = [Dummy()]
shortlisted, removed = evaluate_resumes(uploaded, "job description")
assert len(shortlisted) == 0
assert len(removed) == 1