Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,7 @@ jobs:
- name: Run flake8 (linting)
run: |
poetry run flake8 .

- name: Run pytest (testing)
run: |
poetry run pytest
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@

`poetry run flake8 .`

## Test

`poetry run pytest`

<img width="495" alt="image" src="https://github.com/user-attachments/assets/4a5fa7a5-0c20-480e-8f15-00dfd9c72b2e" />
<img width="802" alt="image" src="https://github.com/user-attachments/assets/5d3dc009-9dce-41bd-b4c9-c660a7c594ad" />

Expand Down
56 changes: 53 additions & 3 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ build-backend = "poetry.core.masonry.api"
black = "^25.1.0"
isort = "^6.0.1"
flake8 = "^7.3.0"
pytest = "^8.4.1"

5 changes: 5 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import os
import sys

# Ensure the app module is importable for all tests
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
62 changes: 62 additions & 0 deletions tests/services/test_search.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import contextlib
from unittest.mock import patch

import pandas as pd
import pytest

from app.services.search import search_companies


@pytest.fixture
def mock_data():
return pd.DataFrame(
{
"Organisation Name": ["Foo Company", "Xyz Motion", "Test Company"],
"Town/City": ["London", "London", "Manchester"],
"County": ["Greater London", "Greater London", "Greater Manchester"],
}
)


# Generalized fixture factory for patching skilled_worker_data_current
@pytest.fixture
def patch_skilled_worker_data_current():
@contextlib.contextmanager
def _patch(data):
with patch(
"app.services.search.skilled_worker_data_current"
) as mock_skilled_worker_data_current:
mock_skilled_worker_data_current.__getitem__.side_effect = data.__getitem__
mock_skilled_worker_data_current.loc.__getitem__.side_effect = (
data.loc.__getitem__
)
yield mock_skilled_worker_data_current

return _patch


def test_exact_match(patch_skilled_worker_data_current, mock_data):
with patch_skilled_worker_data_current(mock_data):
results = search_companies("Foo Company", threshold=90)
assert any("Foo Company" in r.Organisation_Name for r in results)


def test_fuzzy_match(patch_skilled_worker_data_current, mock_data):
with patch_skilled_worker_data_current(mock_data):
results = search_companies("Foo", threshold=70)
assert any("Foo Company" in r.Organisation_Name for r in results)


def test_no_match(patch_skilled_worker_data_current, mock_data):
with patch_skilled_worker_data_current(mock_data):
results = search_companies("Nonexistent Company", threshold=90)
assert not results


def test_nan_handling(patch_skilled_worker_data_current):
nan_data = pd.DataFrame(
{"Organisation Name": [None], "Town/City": [None], "County": [None]}
)
with patch_skilled_worker_data_current(nan_data):
results = search_companies("anything", threshold=0)
assert results[0].Organisation_Name == ""