Skip to content

Commit feed6ff

Browse files
committed
test(ai-agent): add unit tests for POST /transfers/analyse LLM path (#146)
1 parent 4da9fc4 commit feed6ff

1 file changed

Lines changed: 89 additions & 0 deletions

File tree

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
from fastapi.testclient import TestClient
2+
from unittest.mock import MagicMock, patch
3+
import json
4+
import pytest
5+
6+
from main import app
7+
8+
client = TestClient(app)
9+
10+
11+
# Helper to build a fake OpenAI response
12+
def _fake_openai_response(payload: dict):
13+
msg = MagicMock()
14+
msg.content = json.dumps(payload)
15+
choice = MagicMock()
16+
choice.message = msg
17+
resp = MagicMock()
18+
resp.choices = [choice]
19+
return resp
20+
21+
22+
def test_llm_path_flagged_transfer():
23+
with patch("main._openai_client") as mock_client_fn:
24+
mock_client = MagicMock()
25+
mock_client_fn.return_value = mock_client
26+
mock_client.chat.completions.create.return_value = _fake_openai_response(
27+
{"flagged": True, "reason": "Suspicious memo", "confidence": 0.9}
28+
)
29+
response = client.post("/transfers/analyse", json={
30+
"amount": 100.0, "sender": "GABC", "recipient": "GDEF", "memo": "test"
31+
})
32+
assert response.status_code == 200
33+
data = response.json()
34+
assert data["flagged"] is True
35+
assert data["confidence"] == 0.9
36+
37+
38+
def test_llm_path_clean_transfer():
39+
with patch("main._openai_client") as mock_client_fn:
40+
mock_client = MagicMock()
41+
mock_client_fn.return_value = mock_client
42+
mock_client.chat.completions.create.return_value = _fake_openai_response(
43+
{"flagged": False, "reason": None, "confidence": 0.1}
44+
)
45+
response = client.post("/transfers/analyse", json={
46+
"amount": 500.0, "sender": "GABC", "recipient": "GDEF", "memo": "payment"
47+
})
48+
assert response.status_code == 200
49+
data = response.json()
50+
assert data["flagged"] is False
51+
assert isinstance(data["confidence"], float)
52+
53+
54+
def test_llm_path_missing_confidence_defaults_to_zero():
55+
with patch("main._openai_client") as mock_client_fn:
56+
mock_client = MagicMock()
57+
mock_client_fn.return_value = mock_client
58+
mock_client.chat.completions.create.return_value = _fake_openai_response(
59+
{"flagged": False, "reason": None}
60+
)
61+
response = client.post("/transfers/analyse", json={
62+
"amount": 200.0, "sender": "GABC", "recipient": "GDEF", "memo": "normal"
63+
})
64+
assert response.status_code == 200
65+
data = response.json()
66+
assert data["confidence"] == 0.0
67+
68+
69+
def test_llm_path_missing_flagged_defaults_to_false():
70+
with patch("main._openai_client") as mock_client_fn:
71+
mock_client = MagicMock()
72+
mock_client_fn.return_value = mock_client
73+
mock_client.chat.completions.create.return_value = _fake_openai_response(
74+
{"reason": None, "confidence": 0.5}
75+
)
76+
response = client.post("/transfers/analyse", json={
77+
"amount": 300.0, "sender": "GABC", "recipient": "GDEF", "memo": "salary"
78+
})
79+
assert response.status_code == 200
80+
data = response.json()
81+
assert data["flagged"] is False
82+
83+
84+
def test_llm_path_missing_api_key_returns_500(monkeypatch):
85+
monkeypatch.delenv("OPENAI_API_KEY", raising=False)
86+
response = client.post("/transfers/analyse", json={
87+
"amount": 100.0, "sender": "GABC", "recipient": "GDEF", "memo": "test"
88+
})
89+
assert response.status_code == 500

0 commit comments

Comments
 (0)