test_tools.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. from pathlib import Path
  2. from src.tools import AnomalyDetectionTool, BudgetCalculatorTool, CSVImportTool, StatisticsTool, SubscriptionDetectorTool
  3. from src.agents.coordinator import MoneyMirrorCoordinator
  4. from src.agents.transaction_agent import TransactionAgent
  5. from src.memory import SQLiteMemory
  6. from .fakes import FakeRuntime
  7. ROOT = Path(__file__).resolve().parents[1]
  8. def classified_transactions():
  9. memory = SQLiteMemory(":memory:")
  10. imported = CSVImportTool().load(ROOT / "data" / "sample_01.csv")
  11. transactions, _ = TransactionAgent(memory, FakeRuntime()).run(imported)
  12. return memory, transactions
  13. def test_statistics_anomaly_budget_and_subscription_are_data_driven() -> None:
  14. memory, transactions = classified_transactions()
  15. try:
  16. stats = StatisticsTool()
  17. summary = stats.summarize(transactions, "2026-07")
  18. assert summary["income"] == 7600
  19. assert summary["expense"] > 6000
  20. assert stats.patterns(transactions, "2026-07")["late_night"]["count"] >= 3
  21. anomalies = AnomalyDetectionTool().detect(transactions, "2026-07")
  22. assert any(item.merchant == "京东-电脑配件商城" for item in anomalies)
  23. budget = BudgetCalculatorTool().calculate(transactions, "2026-07")
  24. assert budget["categories"]["住房"]["bucket"] == "fixed"
  25. assert budget["categories"]["娱乐"]["bucket"] == "optional"
  26. assert budget["categories"]["餐饮"]["bucket"] == "necessary"
  27. subscriptions = SubscriptionDetectorTool().detect(transactions)
  28. names = {item["merchant"] for item in subscriptions}
  29. assert "腾讯视频会员" in names
  30. assert "房东-六月房租" not in names
  31. assert "星巴克" not in names
  32. assert "万达影院" not in names
  33. assert "滴滴出行" not in names
  34. finally:
  35. memory.close()
  36. def test_hello_agents_registry_exposes_all_deterministic_tools() -> None:
  37. memory, transactions = classified_transactions()
  38. try:
  39. coordinator = MoneyMirrorCoordinator(":memory:", runtime=FakeRuntime())
  40. try:
  41. names = set(coordinator.runtime.status_dict()["registered_tools"])
  42. assert names == {
  43. "CSVImportTool",
  44. "TransactionCategoryTool",
  45. "StatisticsTool",
  46. "AnomalyDetectionTool",
  47. "BudgetCalculatorTool",
  48. "GoalProjectionTool",
  49. "SubscriptionDetectorTool",
  50. "QuestProgressTool",
  51. }
  52. finally:
  53. coordinator.close()
  54. finally:
  55. memory.close()