Brak opisu

test_agent.py 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. """Tests unitaires du graphe LangGraph.
  2. Ces tests sont FOURNIS COMPLETS — ils servent de spécification.
  3. Ils doivent tous passer une fois react_agent.py implémenté.
  4. Le LLM est entièrement mocké : Ollama n'est pas nécessaire.
  5. Lancer : uv run pytest tests/unit/test_agent.py -v
  6. """
  7. from unittest.mock import MagicMock, patch
  8. import pytest
  9. from langchain_core.messages import AIMessage, HumanMessage
  10. from src.agents.react_agent import AgentState, agent_node, should_continue
  11. # ── Helpers ───────────────────────────────────────────────────────────────────
  12. def make_state(messages: list, iterations: int = 0) -> AgentState:
  13. return AgentState(messages=messages, iterations=iterations)
  14. def ai_with_tools() -> AIMessage:
  15. return AIMessage(content="", tool_calls=[
  16. {"name": "search_product", "args": {"name": "laptop"}, "id": "c1", "type": "tool_call"}
  17. ])
  18. def ai_final(content: str = "Voici la réponse.") -> AIMessage:
  19. return AIMessage(content=content)
  20. # ── Tests should_continue ─────────────────────────────────────────────────────
  21. class TestShouldContinue:
  22. def test_returns_tools_when_tool_calls_present(self) -> None:
  23. state = make_state([HumanMessage("test"), ai_with_tools()])
  24. assert should_continue(state) == "tools"
  25. def test_returns_end_when_no_tool_calls(self) -> None:
  26. from langgraph.graph import END
  27. state = make_state([HumanMessage("test"), ai_final()])
  28. assert should_continue(state) == END
  29. def test_returns_end_at_max_iterations(self) -> None:
  30. from langgraph.graph import END
  31. state = make_state([HumanMessage("test"), ai_with_tools()], iterations=20)
  32. assert should_continue(state) == END
  33. def test_continues_below_max_iterations(self) -> None:
  34. state = make_state([HumanMessage("test"), ai_with_tools()], iterations=5)
  35. assert should_continue(state) == "tools"
  36. # ── Tests agent_node ──────────────────────────────────────────────────────────
  37. class TestAgentNode:
  38. def test_increments_iterations(self) -> None:
  39. with patch("src.agents.react_agent.get_llm") as mock:
  40. mock.return_value.bind_tools.return_value.invoke.return_value = ai_final()
  41. result = agent_node(make_state([HumanMessage("test")], iterations=2))
  42. assert result["iterations"] == 3
  43. def test_appends_response_to_messages(self) -> None:
  44. response = ai_final("Réponse test")
  45. with patch("src.agents.react_agent.get_llm") as mock:
  46. mock.return_value.bind_tools.return_value.invoke.return_value = response
  47. result = agent_node(make_state([HumanMessage("test")]))
  48. assert response in result["messages"]
  49. def test_returns_messages_and_iterations_keys(self) -> None:
  50. with patch("src.agents.react_agent.get_llm") as mock:
  51. mock.return_value.bind_tools.return_value.invoke.return_value = ai_final()
  52. result = agent_node(make_state([HumanMessage("test")]))
  53. assert "messages" in result
  54. assert "iterations" in result
  55. def test_binds_tools_to_llm(self) -> None:
  56. with patch("src.agents.react_agent.get_llm") as mock:
  57. mock_llm = MagicMock()
  58. mock_llm.bind_tools.return_value.invoke.return_value = ai_final()
  59. mock.return_value = mock_llm
  60. agent_node(make_state([HumanMessage("test")]))
  61. mock_llm.bind_tools.assert_called_once()
  62. assert len(mock_llm.bind_tools.call_args[0][0]) > 0
  63. # ── Tests build_agent ─────────────────────────────────────────────────────────
  64. class TestBuildAgent:
  65. def test_graph_compiles(self) -> None:
  66. from src.agents.react_agent import build_agent
  67. assert build_agent(use_memory=False) is not None
  68. def test_graph_has_agent_and_tools_nodes(self) -> None:
  69. from src.agents.react_agent import build_agent
  70. app = build_agent(use_memory=False)
  71. ids = list(app.get_graph().nodes.keys())
  72. assert "agent" in ids
  73. assert "tools" in ids
  74. def test_mermaid_is_generated(self) -> None:
  75. from src.agents.react_agent import build_agent
  76. mermaid = build_agent(use_memory=False).get_graph().draw_mermaid()
  77. assert "agent" in mermaid
  78. assert "tools" in mermaid

Powered by TurnKey Linux.