LangChainLangChain 1.4 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
46 small wins to finish your pathNext lesson →

Testing the desk agent

A desk test is a check that sends one message on a fresh thread and reads the reply, one per promise the desk makes. Five of them run in under a second and need no key, which is what makes them worth having.

Last updated: 27 Sep, 2026 · LangChain 1.4

Every test sends one message on a fresh thread and looks at the reply.

A pytest test for the desk

python
# a test sends one message and checks the reply
def test_shipped_order():
    assert "shipped" in ask("ravi", "Where is A17?")

# pytest runs every test_ function in the file
# pytest -q test_desk.py

The ask helper

The helper does the repetitive part. It opens a fresh thread for every call so no test leaks into the next, sends the message as a customer, and returns the desk's last reply.

python
from langgraph.checkpoint.memory import InMemorySaver
from desk import agent
from tools import Customer

THREAD = 0


def ask(who, text):
    global THREAD
    THREAD += 1
    config = {"configurable": {"thread_id": f"t{THREAD}"}}
    result = agent.invoke({"messages": [{"role": "user", "content": text}]}, config,
                          context=Customer(who), version="v2")
    return result.value["messages"][-1].text

Testing the order tools

Each test is one line of intent. The first two go through the order tools: an owner sees their order, and someone else is refused.

python
def test_an_order_is_answered_to_its_owner():
    assert "shipped" in ask("ravi", "Where is A17?")


def test_another_customers_order_is_refused():
    assert "not one of your orders" in ask("mei", "Where is A17?")

Testing policy answers and refusals

The next three cover the policy answer, the refusal for a question no policy covers, and the guardrail that ends the run before the model is reached.

python
def test_a_policy_question_is_answered_from_the_documents():
    assert "5 working days" in ask("ravi", "How long does a refund take?")


def test_an_uncovered_question_is_refused():
    assert "A person will reply" in ask("ravi", "Do you sell gift cards?")


def test_passwords_never_reach_the_model():
    assert "reset link" in ask("ravi", "What is my password?")

Run the tests

One command runs the file. Each dot is a test that sent its message and saw the reply it expected.

Example
pytest -q -p no:warnings test_desk.py

What the five tests cover

  • Five dots, five passes. Each dot is one test that asserted the words that had to appear in the reply.
  • Every path is walked. Two tests go through the order tools, one through the policy search, and one is ended by the guardrail before the model is reached at all.
  • The desk's promises are the tests. The owner check, the policy answer, the refusal for an uncovered question, and the password guardrail each have their own line.
The support desk, one message at a time
Middleware, in orderRavi askswith his card numberno_passwords, ends the runPII masks the cardcall limit caps the loopapproval holds refundscheckpointer saves the threadShopModelthe stand-inlookup_orderowner checkedThe answeror an honest refusalrefund_orderowner checked toosearch_policiesrefunds, shipping, accounts
Hover or tap a piece to see what it is and which lesson built it.
Follow a message

Pick one to watch it run, step by step.

Each test walks one path through the drawing: two through the order tools, one through the policy search, and one that the guardrail ends before the model is reached at all.

When to run the whole file

  • Running the whole file before you change a line, so a red dot tells you which promise you broke.
  • Checking your own logic before a hosted model is added, so a later difference points at the model, not the code.
Watch out. These tests exercise the stand-in model, not a hosted one. Keep them fast and key-free so they run on every change; test against a real provider separately, where the wording of an answer varies from one run to the next.

LangChain is larger than one desk. These are the areas left out above, and what each is for.

TopicWhat it is for
Event streamingstream_events with version="v3": typed events for tokens, tool calls and middleware, recommended for new apps.
HandoffsAgents that pass the whole conversation to another agent, which then talks to the user directly.
SkillsLoading instructions and tools into an agent only when a task needs them.
Custom workflowsMixing fixed steps and agents in one LangGraph graph.
Multi-agent tutorialsA personal assistant with subagents, customer support with handoffs, a knowledge base with a parallel router, and a SQL assistant with skills.
SQL agentAn agent that writes and runs SQL queries against a database.
LangSmith observabilityTracing every run to LangSmith by setting two environment variables.
Integration tests and evalsTesting against real providers, and scoring an agent's answers on a dataset.
Context engineering and memory conceptsThe documentation's guides to what goes into each model call, and to kinds of memory. Lessons 18 and 22 use two of its techniques.
Component architectureDiagrams of how models, tools, retrievers, vector stores and agents fit together.
Runtimes, frameworks and harnessesHow LangChain, LangGraph and Deep Agents relate.
Deep AgentsA ready-made agent on top of LangChain with planning, a virtual filesystem and subagents.
Frontend and Agent Chat UIReact components and a chat interface for LangChain agents.
Deployment and StudioRunning agents on LangSmith's servers and inspecting them in a browser.
Voice agentsSpeech in and out around an agent.
Provider integrationsHundreds of chat models, embedding models, vector stores and loaders, each its own package.
Try it yourself
  • Add a returns policy to POLICIES and a test that asks about returns.
  • Add a test that a refund Mei is not entitled to leaves ORDERS alone.
  • Point DeskModel at a hosted model and run the tests again.

Little by little, you're building something great.