0Pricing
AI Agents · Lezione

Mock delle chiamate LLM nei test

unittest.mock, fixture di pytest e registrazione/riproduzione delle risposte degli LLM

Mock delle chiamate LLM nei test è una lezione AI Agents gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento AI Agents, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso AI Agents include 4 lezioni in totale.

Che cos'è il mocking

Il mocking sostituisce una funzione o un oggetto reale con una versione fittizia che restituisce risposte controllate. Nei test degli agenti, si simulano le chiamate API agli LLM affinché i test vengano eseguiti istantaneamente, non abbiano costi e producano risultati prevedibili.

Il modulo unittest.mock di Python è lo strumento standard per farlo.

Nozioni di base su unittest.mock.patch()

unittest.mock.patch(target) sostituisce temporaneamente l'oggetto indicato per la durata di un test. target è una stringa con notazione a punti che punta all'oggetto così come viene importato nel modulo sottoposto a test.

from unittest.mock import patch, MagicMock

# The function under test calls openai.chat.completions.create
# We patch it so no real API call is made

def ask_llm(question: str) -> str:
    import openai
    client = openai.OpenAI(api_key='test')
    resp = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': question}]
    )
    return resp.choices[0].message.content

with patch('openai.OpenAI') as mock_client_class:
    mock_instance = MagicMock()
    mock_client_class.return_value = mock_instance
    mock_instance.chat.completions.create.return_value = MagicMock(
        choices=[MagicMock(message=MagicMock(content='Paris'))]
    )
    result = ask_llm('Capital of France?')
    print(result)  # 'Paris' — no API call made

Utilizzare patch come decoratore in pytest

Quando viene utilizzato come decoratore con pytest, @patch() inserisce il mock come parametro della funzione. Il mock viene rimosso automaticamente al termine del test.

from unittest.mock import patch, MagicMock
import pytest

# Assume agent.py contains: import openai; client = openai.OpenAI(...)

@patch('agent.openai.OpenAI')
def test_agent_calls_llm(mock_openai_class):
    # Set up the mock chain
    mock_client = MagicMock()
    mock_openai_class.return_value = mock_client
    mock_client.chat.completions.create.return_value = MagicMock(
        choices=[MagicMock(message=MagicMock(content='Paris is the capital of France.'))]
    )

    from agent import ask_llm
    result = ask_llm('What is the capital of France?')

    assert 'Paris' in result
    mock_client.chat.completions.create.assert_called_once()

Creare una risposta mock riutilizzabile

Creare manualmente oggetti risposta mock è prolisso. Crei una funzione di supporto che costruisca oggetti mock strutturati correttamente e conformi alla struttura delle risposte dell'SDK OpenAI.

from unittest.mock import MagicMock

def make_mock_response(content: str, tool_calls: list = None) -> MagicMock:
    message = MagicMock()
    message.content = content
    message.tool_calls = tool_calls or []

    choice = MagicMock()
    choice.message = message
    choice.finish_reason = 'stop' if not tool_calls else 'tool_calls'

    response = MagicMock()
    response.choices = [choice]
    response.usage = MagicMock(total_tokens=42)
    return response

# Usage in tests:
# mock_create.return_value = make_mock_response('Hello!')
# mock_create.return_value = make_mock_response('', tool_calls=[...])

# --- demo ---
response = make_mock_response('The weather in Paris is 18C and sunny.')
print('content:', response.choices[0].message.content)
print('finish_reason:', response.choices[0].finish_reason)
print('total_tokens:', response.usage.total_tokens)

Simulare le chiamate ai tool nelle risposte

Quando testa la logica di chiamata ai tool di un agente, la risposta mock deve includere un campo tool_calls strutturato correttamente, affinché il codice di analisi dell'agente possa elaborarlo senza errori.

import json
from unittest.mock import MagicMock

def make_tool_call_response(tool_name: str, arguments: dict) -> MagicMock:
    tool_call = MagicMock()
    tool_call.id = 'call_abc123'
    tool_call.type = 'function'
    tool_call.function = MagicMock()
    tool_call.function.name = tool_name
    tool_call.function.arguments = json.dumps(arguments)

    message = MagicMock()
    message.content = None
    message.tool_calls = [tool_call]

    response = MagicMock()
    response.choices = [MagicMock(message=message, finish_reason='tool_calls')]
    return response

# mock.return_value = make_tool_call_response('search_web', {'query': 'Python tutorials'})

# --- demo ---
response = make_tool_call_response('search_web', {'query': 'Python tutorials'})
call = response.choices[0].message.tool_calls[0]
print('tool name:', call.function.name)
print('tool arguments:', call.function.arguments)
print('finish_reason:', response.choices[0].finish_reason)

Fixture di pytest per il mocking

Le fixture di pytest consentono di definire codice di configurazione riutilizzabile. Crei una fixture che applichi una patch al client LLM e la fornisca a ogni test che la richiede — senza ripetizioni.

import pytest
from unittest.mock import patch, MagicMock

@pytest.fixture
def mock_openai(make_mock_response):
    with patch('myagent.client.chat.completions.create') as mock_create:
        mock_create.return_value = MagicMock(
            choices=[MagicMock(message=MagicMock(
                content='Default mocked response',
                tool_calls=[]
            ))]
        )
        yield mock_create

# Now any test can use it:
def test_agent_responds(mock_openai):
    from myagent import agent
    result = agent.run('Hello')
    assert result is not None
    mock_openai.assert_called_once()

La fixture mocker di pytest-mock

pytest-mock fornisce una fixture mocker che semplifica l'applicazione delle patch. Pulisce automaticamente i mock e offre una sintassi più chiara rispetto a unittest.mock.patch usato direttamente.

# pip install pytest-mock

# In your test file:
def test_agent_with_mocker(mocker):
    mock_create = mocker.patch('myagent.client.chat.completions.create')
    mock_create.return_value = mocker.MagicMock(
        choices=[mocker.MagicMock(message=mocker.MagicMock(
            content='Mocked answer',
            tool_calls=[]
        ))]
    )

    from myagent import agent
    result = agent.run('What is 2+2?')
    assert 'answer' in result.lower() or '4' in result

    mock_create.assert_called_once()
    # No cleanup needed — mocker handles it

Registrare e riprodurre con vcr.py

vcrpy registra le interazioni HTTP reali in un file «cassetta» alla prima esecuzione, quindi le riproduce nelle esecuzioni successive. È ideale per testare il codice che utilizza l'API HTTP direttamente invece di un SDK.

# pip install vcrpy
import vcr
import httpx

@vcr.use_cassette('fixtures/cassettes/openai_chat.yaml')
def test_with_recorded_response():
    # First run: makes a real HTTP call and records it
    # Subsequent runs: uses the recorded cassette (no network, no cost)
    response = httpx.post(
        'https://api.openai.com/v1/chat/completions',
        json={'model': 'gpt-4o-mini', 'messages': [{'role': 'user', 'content': 'Hello'}]},
        headers={'Authorization': 'Bearer YOUR_KEY'}
    )
    data = response.json()
    assert data['choices'][0]['message']['content'] is not None

Verificare che il mock sia stato chiamato correttamente

Dopo un test, verifichi che il mock sia stato chiamato con gli argomenti corretti. In questo modo è possibile rilevare i bug in cui l'agente invia il modello sbagliato, omette parametri o usa messaggi non corretti.

from unittest.mock import patch, MagicMock, call

@patch('myagent.client.chat.completions.create')
def test_agent_sends_correct_model(mock_create):
    mock_create.return_value = MagicMock(
        choices=[MagicMock(message=MagicMock(content='ok', tool_calls=[]))]
    )

    from myagent import agent
    agent.run('Hello')

    # Verify the mock was called with correct arguments
    mock_create.assert_called_once()
    call_kwargs = mock_create.call_args.kwargs
    assert call_kwargs['model'] == 'gpt-4o-mini'
    assert len(call_kwargs['messages']) >= 1
    assert call_kwargs['messages'][0]['role'] == 'system'

Simulare gli errori API nei test

Verifichi come l'agente gestisce gli errori degli LLM configurando il mock affinché sollevi eccezioni. In questo modo può verificare la gestione degli errori e la logica dei tentativi senza provocare errori API reali.

from unittest.mock import patch
import openai

@patch('myagent.client.chat.completions.create')
def test_agent_handles_rate_limit(mock_create):
    # Simulate a rate limit error
    mock_create.side_effect = openai.RateLimitError(
        message='Rate limit exceeded',
        response=None,
        body=None
    )

    from myagent import agent
    result = agent.run('Hello')

    # Agent should handle this gracefully
    assert result['error'] == 'rate_limit'
    # or
    assert result['retry_after'] is not None

Organizzare le fixture mock in conftest.py

Inserisca le fixture condivise in conftest.py nella directory principale dei test. pytest rileva automaticamente questo file e rende disponibili le fixture a tutti i file di test senza doverle importare.

# tests/conftest.py
import pytest
from unittest.mock import patch, MagicMock

@pytest.fixture(autouse=False)
def mock_llm():
    with patch('myagent.client.chat.completions.create') as mock_create:
        mock_create.return_value = MagicMock(
            choices=[MagicMock(message=MagicMock(
                content='Test response',
                tool_calls=[]
            ))]
        )
        yield mock_create

@pytest.fixture
def mock_search_tool():
    with patch('myagent.tools.search_web') as mock_search:
        mock_search.return_value = [{'title': 'Test', 'url': 'https://example.com'}]
        yield mock_search

Verifica delle conoscenze: simulare le chiamate LLM

Verifichi la propria comprensione delle tecniche di mocking per i test degli agenti.

Riepilogo: simulare le chiamate LLM nei test

Ora dispone degli strumenti per scrivere test unitari degli agenti rapidi e affidabili:

  • Utilizzi unittest.mock.patch() per sostituire i client LLM con dei mock
  • Crei helper riutilizzabili per le risposte mock, conformi alla struttura delle risposte dell'SDK
  • Simuli le chiamate ai tool con campi tool_calls strutturati correttamente
  • Utilizzi le fixture di pytest e conftest.py per condividere i mock tra i test
  • Utilizzi pytest-mock per una sintassi più chiara
  • Utilizzi vcrpy per registrare e riprodurre le interazioni HTTP reali

I mock sono la base di una suite di test per agenti rapida e facile da mantenere.

Domande Frequenti

La lezione «Mock delle chiamate LLM nei test» è gratuita?

Sì — il testo completo di «Mock delle chiamate LLM nei test» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso AI Agents, passa a CoddyKit PRO. Il corso AI Agents include 4 lezioni in totale.

Cosa imparerò in «Mock delle chiamate LLM nei test»?

unittest.mock, fixture di pytest e registrazione/riproduzione delle risposte degli LLM Eserciti AI Agents con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare AI Agents?

Non è richiesta alcuna esperienza precedente. AI Agents su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.

Quanto tempo richiede la lezione «Mock delle chiamate LLM nei test»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione AI Agents?

Sì. Ogni lezione AI Agents include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Perché testare gli agenti è diverso
  2. Mock delle chiamate LLM nei test
  3. Test degli agenti basati su asserzioni
  4. Test di integrazione per le pipeline degli agenti
← Torna a AI Agents