
ChefSpec vérifie qu'une recette déclare les bonnes ressources, en mémoire, sans lancer aucune machine. Il simule la convergence de Chef puis vous laisse affirmer « cette recette installe bien nginx », « ce template notifie bien le rechargement du service ». Un cycle complet tourne en une fraction de seconde, ce qui en fait le premier filet de sécurité avant toute convergence sur une vraie VM. Ce guide teste le cookbook webstack du volet précédent. Public visé : lecteur ayant structuré un cookbook, à l'aise avec les ressources Chef.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Écrire un test ChefSpec pour une recette avec
spec_helperet unSoloRunner. - Vérifier qu'une ressource est déclarée avec ses propriétés (mode, contenu).
- Tester une notification entre ressources sans rien exécuter.
- Éviter le rapport de couverture déprécié, que Cookstyle rejette.
- Situer ChefSpec, test unitaire, face à InSpec, test d'intégration.
Prérequis
Section intitulée « Prérequis »- Le cookbook
webstackdu guide Structurer un cookbook, avec ses recettesinstalletconfig. - CINC Workstation sur votre poste : ChefSpec y est déjà inclus, rien à installer.
Aucune VM n'est nécessaire : ChefSpec s'exécute entièrement sur votre poste. Testé avec ChefSpec 9.3.8 (CINC Workstation), cookbook webstack 1.0.0.
ChefSpec, le test unitaire de Chef
Section intitulée « ChefSpec, le test unitaire de Chef »Un cookbook mérite deux niveaux de tests, qui répondent à deux questions différentes. ChefSpec répond à « ma recette déclare-t-elle les bonnes ressources, avec les bonnes propriétés et les bonnes notifications ? ». Il compile la recette et joue la convergence en mémoire, sans toucher à un système. InSpec répond à « la machine est-elle réellement dans l'état voulu après convergence ? » et s'exécute sur la vraie VM.
| ChefSpec | InSpec | |
|---|---|---|
| Niveau | Unitaire | Intégration |
| Vérifie | Ce que la recette déclare | L'état réel de la machine |
| Cible | En mémoire, sur le poste | La VM convergée |
| Vitesse | Fraction de seconde | Dizaines de secondes |
| Attrape | Erreur de logique de recette | Écart entre intention et résultat |
Les deux sont complémentaires : ChefSpec avant de converger, pour un retour immédiat sur la logique ; InSpec après knife zero converge, pour prouver le résultat sur une vraie machine. Ce guide couvre le premier.
Écrire un premier test
Section intitulée « Écrire un premier test »ChefSpec s'appuie sur RSpec, le framework de test Ruby. On place les tests dans un dossier spec/ à la racine du cookbook. Un fichier spec_helper.rb charge ChefSpec une fois pour tous les tests.
-
Créer le helper
spec/spec_helper.rb:require "chefspec" -
Écrire le test de la recette
installdansspec/unit/recipes/install_spec.rb:require "spec_helper"describe "webstack::install" dolet(:chef_run) { ChefSpec::SoloRunner.new(platform: "ubuntu", version: "24.04").converge(described_recipe) }it "met a jour le cache apt" doexpect(chef_run).to update_apt_update("mise a jour du cache")endit "installe le paquet nginx" doexpect(chef_run).to install_package("nginx")endend
Trois éléments portent tout le test. Le SoloRunner simule un nœud : on lui donne une plateforme (ubuntu 24.04) pour que Chef connaisse les attributs par défaut de ce système, puis il converge la recette en mémoire. described_recipe reprend automatiquement le nom du describe (ici webstack::install). Enfin, les matchers comme install_package ou update_apt_update affirment qu'une ressource est déclarée avec la bonne action : le matcher install_package vérifie une ressource package dont l'action est :install.
Lancer les tests
Section intitulée « Lancer les tests »On exécute les tests avec chef exec rspec, qui utilise le RSpec embarqué dans CINC Workstation. Le drapeau --format documentation affiche chaque test par son intitulé.
cd ~/chef-parc/cookbooks/webstackchef exec rspec --format documentationLa sortie liste les tests réussis :
webstack::install met a jour le cache apt installe le paquet nginx
Finished in 0.16 seconds (files took 1.25 seconds to load)2 examples, 0 failuresDeux vérifications en 0,16 seconde, sans qu'aucune machine n'ait démarré. C'est cette rapidité qui permet de relancer les tests à chaque modification de la recette.
Tester la recette de configuration
Section intitulée « Tester la recette de configuration »La recette config est plus riche : un répertoire, un template, un fichier et un service. ChefSpec sait vérifier chaque ressource et ses propriétés. On crée spec/unit/recipes/config_spec.rb :
require "spec_helper"
describe "webstack::config" do let(:chef_run) { ChefSpec::SoloRunner.new(platform: "ubuntu", version: "24.04").converge(described_recipe) }
it "cree le repertoire racine" do expect(chef_run).to create_directory("/var/www/webstack").with(mode: "0755") end
it "depose le template de configuration nginx" do expect(chef_run).to create_template("/etc/nginx/conf.d/webstack.conf") end
it "cree la page index" do expect(chef_run).to create_file("/var/www/webstack/index.html").with(content: "webstack\n") end
it "active et demarre nginx" do expect(chef_run).to enable_service("nginx") expect(chef_run).to start_service("nginx") endendLa méthode .with(...) est la clé : elle ne vérifie pas seulement que la ressource existe, mais qu'elle porte les bonnes propriétés. Ici on prouve que le répertoire a le mode 0755 et que la page d'accueil contient bien le texte attendu. Un service se teste par deux matchers distincts, enable_service et start_service, car la recette déclare les deux actions.
Vérifier une notification
Section intitulée « Vérifier une notification »Le point le plus utile de ChefSpec est de tester ce qu'un simple coup d'oeil au code ne garantit pas : les notifications. La recette recharge nginx uniquement quand le template change. On vérifie ce lien sans exécuter quoi que ce soit, en ajoutant à config_spec.rb :
it "le template notifie le rechargement de nginx" do resource = chef_run.template("/etc/nginx/conf.d/webstack.conf") expect(resource).to notify("service[nginx]").to(:reload).delayedendOn récupère la ressource template, puis on affirme qu'elle notifie service[nginx] avec l'action :reload en mode :delayed. Si quelqu'un remplace un jour :reload par :restart, ou passe la notification en :immediately, ce test échoue immédiatement, avant même de toucher une machine.
Le rapport de couverture est déprécié
Section intitulée « Le rapport de couverture est déprécié »Beaucoup de tutoriels vous feront ajouter un rapport de couverture dans
spec_helper.rb, avec ChefSpec::Coverage.start! et un at_exit appelant
ChefSpec::Coverage.report!. Ne le faites pas : cette fonctionnalité est
dépréciée par Chef. Elle fonctionne encore, mais Cookstyle la signale comme
une faute :
Chef/Deprecations/ChefSpecCoverageReport: Don't use the deprecated ChefSpeccoverage report functionality in your specs.La contradiction serait absurde : vous ajouteriez volontairement une ligne que le linter du même écosystème vous demandera de retirer, et qui fera échouer votre CI dès que vous brancherez Cookstyle.
La bonne façon de savoir si un cookbook est bien testé n'est donc pas un pourcentage, mais une relecture : pour chaque ressource déclarée dans vos recettes, existe-t-il une attente correspondante dans les specs ? Sur un cookbook de quelques ressources, la question se tranche en un coup d'œil, et elle vous dit quoi tester plutôt que combien.
Voir un test échouer
Section intitulée « Voir un test échouer »Un test n'a de valeur que s'il échoue quand il le doit. Simulez une régression en affirmant, à tort, que la recette installe apache2 :
it "installe apache2" do expect(chef_run).to install_package("apache2")endChefSpec refuse et explique clairement l'écart :
Failures: 1) webstack::install installe apache2 Failure/Error: expect(chef_run).to install_package("apache2") expected "package[apache2]" with action :install to be in Chef run.
1 example, 1 failureC'est exactement ce qu'on attend d'un test : si une modification casse la logique de la recette, ChefSpec le signale en une fraction de seconde, avant la moindre convergence sur une VM. Retirez ensuite ce test volontairement faux.
Où ranger les tests
Section intitulée « Où ranger les tests »La convention Chef place les tests unitaires sous spec/unit/recipes/, un fichier *_spec.rb par recette. Cette arborescence est reconnue automatiquement par chef exec rspec, et un outil d'intégration continue la retrouve sans configuration. Gardez un spec_helper.rb unique à la racine de spec/, dont le seul rôle est de charger ChefSpec.
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À retenir
Section intitulée « À retenir »- ChefSpec teste ce qu'une recette déclare, en mémoire, sans lancer de VM.
- Un test tient en trois éléments : un
SoloRunner,described_recipe, et des matchers (install_package,create_template, ...). .with(...)vérifie les propriétés d'une ressource, pas seulement son existence.- Les notifications sont testables unitairement :
notify(...).to(:reload).delayed. - Le rapport de couverture est déprécié : Cookstyle le rejette, ne l'activez pas.
- ChefSpec est le test unitaire (avant convergence) ; InSpec est le test d'intégration (après
knife zero convergesur la vraie VM).