| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- """Tests unitaires du graphe LangGraph.
-
- Ces tests sont FOURNIS COMPLETS — ils servent de spécification.
- Ils doivent tous passer une fois react_agent.py implémenté.
- Le LLM est entièrement mocké : Ollama n'est pas nécessaire.
-
- Lancer : uv run pytest tests/unit/test_agent.py -v
- """
-
- from unittest.mock import MagicMock, patch
-
- import pytest
- from langchain_core.messages import AIMessage, HumanMessage
-
- from src.agents.react_agent import AgentState, agent_node, should_continue
-
-
- # ── Helpers ───────────────────────────────────────────────────────────────────
-
- def make_state(messages: list, iterations: int = 0) -> AgentState:
- return AgentState(messages=messages, iterations=iterations)
-
- def ai_with_tools() -> AIMessage:
- return AIMessage(content="", tool_calls=[
- {"name": "search_product", "args": {"name": "laptop"}, "id": "c1", "type": "tool_call"}
- ])
-
- def ai_final(content: str = "Voici la réponse.") -> AIMessage:
- return AIMessage(content=content)
-
-
- # ── Tests should_continue ─────────────────────────────────────────────────────
-
- class TestShouldContinue:
-
- def test_returns_tools_when_tool_calls_present(self) -> None:
- state = make_state([HumanMessage("test"), ai_with_tools()])
- assert should_continue(state) == "tools"
-
- def test_returns_end_when_no_tool_calls(self) -> None:
- from langgraph.graph import END
- state = make_state([HumanMessage("test"), ai_final()])
- assert should_continue(state) == END
-
- def test_returns_end_at_max_iterations(self) -> None:
- from langgraph.graph import END
- state = make_state([HumanMessage("test"), ai_with_tools()], iterations=20)
- assert should_continue(state) == END
-
- def test_continues_below_max_iterations(self) -> None:
- state = make_state([HumanMessage("test"), ai_with_tools()], iterations=5)
- assert should_continue(state) == "tools"
-
-
- # ── Tests agent_node ──────────────────────────────────────────────────────────
-
- class TestAgentNode:
-
- def test_increments_iterations(self) -> None:
- with patch("src.agents.react_agent.get_llm") as mock:
- mock.return_value.bind_tools.return_value.invoke.return_value = ai_final()
- result = agent_node(make_state([HumanMessage("test")], iterations=2))
- assert result["iterations"] == 3
-
- def test_appends_response_to_messages(self) -> None:
- response = ai_final("Réponse test")
- with patch("src.agents.react_agent.get_llm") as mock:
- mock.return_value.bind_tools.return_value.invoke.return_value = response
- result = agent_node(make_state([HumanMessage("test")]))
- assert response in result["messages"]
-
- def test_returns_messages_and_iterations_keys(self) -> None:
- with patch("src.agents.react_agent.get_llm") as mock:
- mock.return_value.bind_tools.return_value.invoke.return_value = ai_final()
- result = agent_node(make_state([HumanMessage("test")]))
- assert "messages" in result
- assert "iterations" in result
-
- def test_binds_tools_to_llm(self) -> None:
- with patch("src.agents.react_agent.get_llm") as mock:
- mock_llm = MagicMock()
- mock_llm.bind_tools.return_value.invoke.return_value = ai_final()
- mock.return_value = mock_llm
- agent_node(make_state([HumanMessage("test")]))
- mock_llm.bind_tools.assert_called_once()
- assert len(mock_llm.bind_tools.call_args[0][0]) > 0
-
-
- # ── Tests build_agent ─────────────────────────────────────────────────────────
-
- class TestBuildAgent:
-
- def test_graph_compiles(self) -> None:
- from src.agents.react_agent import build_agent
- assert build_agent(use_memory=False) is not None
-
- def test_graph_has_agent_and_tools_nodes(self) -> None:
- from src.agents.react_agent import build_agent
- app = build_agent(use_memory=False)
- ids = list(app.get_graph().nodes.keys())
- assert "agent" in ids
- assert "tools" in ids
-
- def test_mermaid_is_generated(self) -> None:
- from src.agents.react_agent import build_agent
- mermaid = build_agent(use_memory=False).get_graph().draw_mermaid()
- assert "agent" in mermaid
- assert "tools" in mermaid
|