Logo Cucumber

Cucumber

Le framework de développement piloté par le comportement (BDD) qui permet d'écrire des tests d'acceptation en langage naturel, facilitant la collaboration entre les équipes techniques et non techniques.

Pour les non-initiés

Qu'est-ce que Cucumber ?

Imaginez que vous développez une application et que vous souhaitez vous assurer qu'elle fonctionne exactement comme prévu. Comment faire pour que tout le monde dans l'équipe - des développeurs aux responsables métier en passant par les testeurs - comprenne exactement ce qui est attendu ? C'est là qu'intervient Cucumber.

Cucumber est comme un traducteur universel entre le langage des affaires et le code informatique. Il permet d'écrire le comportement attendu de votre application en langage naturel, dans des termes que tout le monde peut comprendre - puis de transformer automatiquement ces descriptions en tests qui vérifient que votre application fonctionne correctement.

Ce que Cucumber apporte à votre projet

Communication claire

Tout le monde parle le même langage, ce qui réduit les malentendus et assure que ce qui est construit correspond vraiment à ce qui est attendu par les utilisateurs finaux.

Confiance accrue

Les tests automatiques basés sur les scénarios Cucumber vous assurent que l'application fait ce qu'elle est censée faire, même après des modifications du code.

Documentation vivante

Les scénarios Cucumber servent à la fois de spécifications et de tests, créant une documentation toujours à jour qui évolue avec votre application.

Développement agile

Parfaitement adapté aux méthodes agiles, Cucumber aide à définir clairement les critères d'acceptation et à vérifier automatiquement qu'ils sont respectés à chaque itération.

En résumé, Cucumber améliore la collaboration entre les équipes techniques et non techniques, réduit les erreurs de communication, et assure que l'application développée correspond exactement aux besoins des utilisateurs. C'est un outil précieux pour tout projet où la qualité et la conformité aux attentes des utilisateurs sont essentielles.

Pour les développeurs

Fonctionnement technique

Icône CucumberCucumber est un framework de test BDD (Behavior-Driven Development) qui exécute des spécifications écrites en langage naturel. Il est disponible dans plusieurs langages de programmation, mais nous nous concentrerons ici sur son implémentation en Icône JavaScript/Node.jsJavaScript/Node.js via le package @cucumber/cucumber.

Architecture et composants

Cucumber s'articule autour de trois composants principaux :

  • Features (Fonctionnalités) - Fichiers .feature écrits en Gherkin qui décrivent le comportement attendu
  • Step Definitions (Définitions d'étapes) - Code qui transforme les phrases en Gherkin en actions exécutables
  • Support Code - Hooks, World et autres configurations qui soutiennent l'exécution des tests

Exemples pratiques avec Node.js

Fichier de feature (Gherkin)

Les fichiers .feature contiennent des scénarios écrits en Gherkin qui décrivent le comportement attendu :

features/login.feature
# features/login.feature Feature: Authentification utilisateur En tant qu'utilisateur inscrit Je veux pouvoir me connecter à l'application Afin d'accéder aux fonctionnalités réservées aux membres Background: Given je suis sur la page d'accueil Scenario: Connexion réussie When je clique sur "Connexion" And je remplis le champ "email" avec "utilisateur@exemple.fr" And je remplis le champ "password" avec "motdepasse123" And je clique sur le bouton "Se connecter" Then je devrais voir "Bienvenue, utilisateur@exemple.fr" And je devrais être sur la page "tableau-de-bord" Scenario: Connexion échouée When je clique sur "Connexion" And je remplis le champ "email" avec "utilisateur@exemple.fr" And je remplis le champ "password" avec "mauvais_mot_de_passe" And je clique sur le bouton "Se connecter" Then je devrais voir "Identifiants invalides" And je devrais être sur la page "connexion"

Step Definitions

Les step definitions font le lien entre le langage Gherkin et le code d'automatisation :

features/step_definitions/login_steps.js
// features/step_definitions/login_steps.js const { Given, When, Then } = require('@cucumber/cucumber'); const { By, until } = require('selenium-webdriver'); const { expect } = require('chai'); // Hooks pour le setup et teardown const { Before, After } = require('@cucumber/cucumber'); const { Builder } = require('selenium-webdriver'); // Initialiser le driver avant chaque scénario Before(async function() { this.driver = await new Builder().forBrowser('chrome').build(); await this.driver.manage().window().setRect({ width: 1280, height: 800 }); this.vars = {}; }); // Fermer le driver après chaque scénario After(async function() { if (this.driver) { await this.driver.quit(); } }); // Step definitions Given('je suis sur la page d\'accueil', async function() { await this.driver.get('https://example.com'); }); When('je clique sur {string}', async function(linkText) { await this.driver.findElement(By.linkText(linkText)).click(); }); When('je remplis le champ {string} avec {string}', async function(fieldName, value) { await this.driver.findElement(By.name(fieldName)).sendKeys(value); }); When('je clique sur le bouton {string}', async function(buttonText) { await this.driver.findElement(By.xpath(`//button[contains(text(), '${buttonText}')]`)).click(); }); Then('je devrais voir {string}', async function(expectedText) { const pageSource = await this.driver.getPageSource(); expect(pageSource).to.include(expectedText); }); Then('je devrais être sur la page {string}', async function(pagePath) { await this.driver.wait(until.urlContains(pagePath), 5000); const currentUrl = await this.driver.getCurrentUrl(); expect(currentUrl).to.include(pagePath); });

Configuration de Cucumber

La configuration de Cucumber se fait via un fichier cucumber.js :

cucumber.js
// cucumber.js module.exports = { default: { parallel: 2, format: ['html:cucumber-report.html', 'json:cucumber-report.json', 'summary'], paths: ['features/**/*.feature'], require: ['features/step_definitions/**/*.js', 'features/support/**/*.js'], publishQuiet: true, worldParameters: { baseUrl: 'https://example.com' }, tags: 'not @wip and not @skip' }, // Configuration pour les tests de régression regression: { format: ['html:cucumber-regression-report.html'], paths: ['features/**/*.feature'], require: ['features/step_definitions/**/*.js', 'features/support/**/*.js'], tags: '@regression and not @skip' }, // Configuration pour les tests de fumée smoke: { format: ['html:cucumber-smoke-report.html'], paths: ['features/**/*.feature'], require: ['features/step_definitions/**/*.js', 'features/support/**/*.js'], tags: '@smoke and not @skip' } }; // Dans package.json, vous pourriez alors avoir : // // "scripts": { // "test": "cucumber-js", // "test:regression": "cucumber-js --profile regression", // "test:smoke": "cucumber-js --profile smoke" // }

World et support

Le "World" est un contexte partagé entre les étapes d'un scénario :

features/support/world.js
// features/support/world.js const { setWorldConstructor, World } = require('@cucumber/cucumber'); const { Builder } = require('selenium-webdriver'); const chrome = require('selenium-webdriver/chrome'); const firefox = require('selenium-webdriver/firefox'); const { Options } = require('selenium-webdriver/chrome'); /** * Classe personnalisée pour le World Cucumber * Permet de partager le contexte entre les steps d'un scénario */ class CustomWorld extends World { constructor(options) { super(options); this.baseUrl = options.parameters.baseUrl || 'https://example.com'; this.testId = `test-${Date.now()}`; this.screenshot = null; } // Méthode pour initialiser le driver avec différentes options async buildDriver(browserName = 'chrome', headless = false) { let driver; if (browserName === 'chrome') { const options = new Options(); if (headless) { options.addArguments('--headless'); } options.addArguments('--no-sandbox'); options.addArguments('--disable-dev-shm-usage'); options.addArguments('--window-size=1280,800'); driver = await new Builder() .forBrowser('chrome') .setChromeOptions(options) .build(); } else if (browserName === 'firefox') { const options = new firefox.Options(); if (headless) { options.addArguments('-headless'); } driver = await new Builder() .forBrowser('firefox') .setFirefoxOptions(options) .build(); } else { throw new Error(`Navigateur non supporté: ${browserName}`); } this.driver = driver; return driver; } // Méthode pour naviguer vers une URL relative async visit(path) { const url = path.startsWith('http') ? path : `${this.baseUrl}${path}`; await this.driver.get(url); } // Méthode pour prendre une capture d'écran async takeScreenshot() { if (this.driver) { this.screenshot = await this.driver.takeScreenshot(); } return this.screenshot; } } // Enregistrer notre monde personnalisé setWorldConstructor(CustomWorld);

Installation et démarrage rapide

Pour commencer avec Cucumber.js, installez les packages nécessaires :

npm install --save-dev @cucumber/cucumber chai selenium-webdriver @cucumber/pretty-formatter

Structure de dossiers typique d'un projet Cucumber :

features/ ├── step_definitions/ # Définitions des étapes │ ├── login_steps.js │ └── navigation_steps.js ├── support/ # Code de support │ ├── hooks.js # Before, After hooks │ └── world.js # Contexte partagé └── login.feature # Fichiers de scénarios

Fonctionnalités avancées

  • Tags - Permettent de catégoriser et filtrer les scénarios (@regression, @smoke, @wip, etc.)
  • Data Tables - Pour fournir des données structurées aux étapes
  • Doc Strings - Pour inclure des blocs de texte plus grands
  • Scenario Outlines - Pour exécuter le même scénario avec différentes données
  • Hooks - Before, After, BeforeAll, AfterAll pour la configuration et le nettoyage
  • Attachements - Pour enrichir les rapports avec des captures d'écran, logs, etc.
  • Parameterized Step Definitions - Pour réutiliser les étapes avec des paramètres différents

Intégration avec d'autres outils

Cucumber s'intègre bien avec différents outils pour former une solution de test complète :

  • Icône Selenium WebDriverSelenium WebDriver - Pour les tests end-to-end d'applications web
  • Puppeteer / Playwright - Alternatives modernes à Selenium pour contrôler les navigateurs
  • Appium - Pour tester des applications mobiles
  • REST API clients - Pour tester des Icône API RESTAPI REST
  • Formatters et reporters - Pour générer des rapports HTML, JSON, JUnit, etc.
  • CI/CD - Intégration dans les pipelines Jenkins, Icône GitHub ActionsGitHub Actions, GitLab CI, etc.

Bonnes pratiques

  • Principes BRIEF - Business language, Real data, Intention revealing, Essential, Focused
  • Un scénario = un comportement - Chaque scénario doit tester un seul aspect fonctionnel
  • Autonomie des scénarios - Les scénarios doivent être indépendants les uns des autres
  • Favoriser la réutilisation - Créer des étapes réutilisables et des helpers
  • Éviter les détails d'implémentation - Se concentrer sur le comportement, pas sur la façon dont il est implémenté
  • Utiliser un langage commun - Maintenir un glossaire des termes métier partagés
  • Éviter les scénarios trop techniques - Les features doivent rester compréhensibles par les non-développeurs

Cucumber est un outil puissant qui, lorsqu'il est bien utilisé, peut considérablement améliorer la qualité des logiciels et la communication entre les équipes techniques et non techniques. Il encourage une approche collaborative du développement où les spécifications sont écrites ensemble et où les tests servent à la fois de documentation et de validation continue.

Applications concrètes

Cas d'usage

Spécification par l'exemple

Ateliers collaboratifs où les équipes métier, développement et qualité définissent ensemble des exemples concrets du comportement attendu, qui seront ensuite automatisés avec Cucumber.

Tests d'acceptation utilisateur

Validation que l'application répond aux critères d'acceptation définis par les utilisateurs, avec des tests exprimés dans le langage du domaine métier et automatisés pour une exécution régulière.

Documentation vivante

Création d'une documentation fonctionnelle toujours à jour, qui sert à la fois de référence pour les utilisateurs et de tests automatisés pour les développeurs, assurant que la documentation ne diverge jamais du comportement réel.

Intégration continue

Exécution automatique des tests Cucumber dans les pipelines CI/CD, permettant de vérifier que chaque changement respecte les comportements attendus et de générer des rapports détaillés sur les fonctionnalités validées.

Refactoring en confiance

Support lors de la modernisation d'applications legacy, en assurant que les comportements critiques sont bien documentés et testés avant et après les modifications majeures du code.

Tests de régression planifiés

Exécution régulière de suites de tests complètes pour vérifier que les fonctionnalités critiques continuent de fonctionner correctement à mesure que l'application évolue.

Exemple de workflow BDD avec Cucumber

Voici un workflow typique d'utilisation de Cucumber dans un contexte d'équipe agile :

  1. Atelier de découverte - L'équipe (PO, développeurs, testeurs) se réunit pour discuter d'une nouvelle fonctionnalité
  2. Rédaction collaborative des scénarios - Les exemples concrets du comportement attendu sont écrits en Gherkin
  3. Implémentation des step definitions - Les développeurs et testeurs automatisent les scénarios
  4. Les tests échouent - Les scénarios sont exécutés et échouent car la fonctionnalité n'est pas encore implémentée
  5. Développement de la fonctionnalité - Les développeurs codent la fonctionnalité pour satisfaire les scénarios
  6. Les tests passent - Les scénarios sont à nouveau exécutés et réussissent
  7. Intégration et tests de régression - Les scénarios sont intégrés à la suite de tests automatisés
  8. Documentation générée - Des rapports HTML sont générés pour documenter les fonctionnalités

Ce flux de travail cyclique garantit que les fonctionnalités développées répondent exactement aux attentes des parties prenantes, et que les comportements validés restent fonctionnels au fil du temps.