Tester dans les deux modes
Deux niveaux de tests
flowchart LR
subgraph S["Sans clé (pytest)"]
F["FakeClient"] --> L["logique : coût, réessais, JSON, Markdown, chat, mode"]
end
subgraph R["Avec le vrai modèle"]
A["Mode clé d'API"] --> E["tokens, resume, --stream, chat"]
V["Mode Vertex AI"] --> E
end
S --> R
| Tests pytest | Test de bout en bout | |
|---|---|---|
| Clé ou projet nécessaire | non | oui |
| Durée | moins d'une seconde | de quelques secondes à une minute |
| Coût | nul | quelques fractions de centime |
| Ce qu'il prouve | le code fait ce qu'on croit | l'ensemble marche avec le vrai service et donne des résultats sensés |
Le faux client
FakeClient imite les quatre points d'entrée utilisés (models.generate_content, models.generate_content_stream, models.count_tokens, chats.create). Il renvoie des réponses préparées, ou lève une erreur pour simuler un incident :
class FakeClient:
def __init__(self, *reponses):
self.reponses = list(reponses)
self.appels = []
self.models = self
self.chats = self
def _suivante(self, **kw):
self.appels.append(kw)
r = self.reponses.pop(0)
if isinstance(r, Exception):
raise r
return rChaque test prépare un scénario et vérifie le résultat et les appels effectués (par exemple, que la config contient bien le schéma JSON). Code complet : test_reunion.py.
pip install -r requirements.txt
pytest -qLe test de bout en bout
python reunion.py tokens reunion_exemple.txt
python reunion.py resume reunion_exemple.txt
python reunion.py resume reunion_exemple.txt --stream
printf "Qui prépare le message aux clients ?\nEt quand est-il validé ?\n\n" | python reunion.py chat reunion_exemple.txtgcloud auth application-default login # une seule fois
export GOOGLE_GENAI_USE_VERTEXAI=TRUE GOOGLE_CLOUD_PROJECT=mon-projet-gcp
export MODEL=gemini-2.5-flash # voir la leçon Vertex AI
# puis les mêmes quatre commandesQue prouve test_compte_rendu_structure, qui utilise FakeClient ?
Le faux client ne juge pas la qualité du modèle : il vérifie notre code (paramètres envoyés, validation, calcul). La qualité se juge au test de bout en bout, en relisant.
Le mode Vertex AI nécessite-t-il de supprimer quelque chose après le test ?
Les appels à generate_content ne créent ni endpoint, ni bucket, ni service. Seule la consommation est facturée au projet.
Résultat obtenu
Tests sans clé, 2026-10-15 :
test_reunion.py::test_mode[TRUE-Vertex AI] PASSED [ 85%]
test_reunion.py::test_mode[false-cl\xe9 d'API] PASSED [ 92%]
test_reunion.py::test_mode[-cl\xe9 d'API] PASSED [100%]
============================== 14 passed in 0.29s ==============================Bout en bout en mode clé d'API (gemini-3.5-flash) :
[mode : clé d'API | modèle : gemini-3.5-flash]
302 tokens en entrée, soit environ 0.000091 $ avant la réponse
[coût estimé : 0.003344 $]
1. Le lancement de la v2 de l'application est officiellement décalé au 4 novembre.
2. Karim analyse cette semaine le problème d'export PDF sur les gros fichiers.
...
> Et quand est-il validé ?
Le message sera validé lundi (par Inès et Léa).Bout en bout en mode Vertex AI (projet de test, gemini-2.5-flash, région global puis europe-west1) :
[mode : Vertex AI | modèle : gemini-2.5-flash]
301 tokens en entrée, soit environ 0.000090 $ avant la réponse
[coût estimé : 0.002226 $]
| Examiner le problème d'export PDF sur les gros fichiers | Karim | cette semaine |
| Envoyer les captures d'écran de la v2 à Thomas pour la page d'accueil | Karim | vendredi |
| Préparer le message pour informer les clients du nouveau calendrier | Léa | lundi |
...
=== europe-west1
| Terminer les tests de bout en bout du module de paiement | Karim | non précisé |
| Préparer le message pour prévenir les clients du nouveau calendrier | Léa | non précisé |Les quatre commandes fonctionnent dans les deux modes, sans changer une ligne de code. Les comptes rendus diffèrent d'un modèle et d'un appel à l'autre (ici, une action « tests de paiement » apparaît en europe-west1) : les deux sont défendables, c'est pourquoi on relit avant de diffuser. Rien n'a été créé dans le projet Google Cloud, il n'y a donc rien à nettoyer.
Exercice final
Ajoutez une commande actions qui n'affiche que le tableau des actions, et le test sans clé correspondant.
Voir la solution
p.add_argument("commande", choices=["resume", "tokens", "chat", "actions"])
...
elif args.commande == "actions":
cr, _ = compte_rendu(client, transcription)
print(en_markdown(cr).split("## Actions\n", 1)[1])def test_commande_actions(monkeypatch, tmp_path, capsys):
f = tmp_path / "r.txt"
f.write_text("Inès : on décale.", encoding="utf-8")
monkeypatch.setattr(reunion, "make_client",
lambda: FakeClient(NS(text=json.dumps(CR), usage_metadata=USAGE)))
reunion.main(["actions", str(f)])
out = capsys.readouterr().out
assert "| Prévenir le support | Inès | vendredi |" in out and "Résumé" not in outmonkeypatch.setattr(reunion, "make_client", ...) remplace la création du vrai client : main() tourne entièrement, sans clé. C'est le même principe que pour toutes les autres fonctions, appliqué à tout le programme.
Je sais faire
- Écrire un faux client et tester un programme qui appelle Gemini sans clé
- Lancer un test de bout en bout en mode clé d'API puis en mode Vertex AI
- Rendre une conversation scriptable avec un tube
- Expliquer pourquoi aucune ressource cloud n'est à nettoyer après ces appels