Un flux de travail BDD avec Behat et Phpspec

Dans ce didacticiel, nous examinerons deux outils BDD différents, Behat et phpspec, et verrons comment ils peuvent vous aider dans votre processus de développement. Apprendre BDD peut être déroutant. Nouvelle méthodologie, nouveaux outils et de nombreuses questions, telles que "quoi tester?" et "quels outils utiliser?". J'espère que cet exemple assez simple vous donnera des idées sur la manière d'intégrer BDD dans votre propre flux de travail..

Mon inspiration

Je me suis inspiré pour écrire ce tutoriel de Taylor Otwell, créateur du framework Laravel. A plusieurs reprises, j'ai entendu Taylor expliquer pourquoi il ne faisait généralement pas TDD / BDD en disant qu'il aime d'abord planifier l'API de son code, avant de commencer à le mettre en œuvre. J'ai entendu cela de la part de nombreux développeurs et à chaque fois, je me disais: "Mais c'est le cas d'utilisation idéal pour TDD / BDD!". Taylor dit qu'il aime cartographier l'API de son code, en écrivant le code qu'il souhaite avoir. Il commencera alors à coder et ne sera pas satisfait tant qu'il n'aura pas atteint cette API exacte. L'argument est logique si vous testez / spécifiez uniquement au niveau de l'unité, mais en utilisant un outil comme Behat, vous commencez par le comportement externe de votre logiciel, qui est fondamentalement ce que Taylor veut accomplir..

Ce que nous allons couvrir

Dans ce tutoriel, nous allons construire une simple classe de chargeur de fichiers de configuration. Nous allons commencer par utiliser l'approche de Taylor puis passer à une approche BDD. Les exemples sont minimalistes, mais nous devrons tout de même nous soucier des fixtures, des méthodes statiques, etc., donc, dans l'ensemble, je pense qu'ils devraient être suffisants pour montrer comment Behat et phpspec peuvent se compléter..

Avertissement: Tout d’abord, cet article n’est pas un commencer guider. Il suppose une connaissance de base de BDD, Behat et phpspec. Vous avez probablement déjà examiné ces outils, mais vous avez encore du mal à les utiliser dans votre flux de travail quotidien. Si vous voulez améliorer phpspec, jetez un coup d'œil à mon tutoriel d'initiation. Deuxièmement, j'utilise Taylor Otwell à titre d'exemple. Je ne sais rien du fonctionnement de Taylor, à part ce que je l'ai entendu dire dans des podcasts, etc. Je l'utilise comme exemple parce qu'il est un développeur génial (il a créé Laravel!) Et qu'il est connu. J'aurais aussi bien pu utiliser quelqu'un d'autre, car la plupart des développeurs, y compris moi-même, ne font pas encore BDD tout le temps. En outre, je ne dis pas que le flux de travail décrit par Taylor est mauvais. Je pense que c'est une idée brillante de réfléchir dans votre code avant de l'écrire. Ce tutoriel n'a pour but que de montrer la manière de procéder de BDD.

Le flux de travail de Taylor

Commençons par examiner comment Taylor pourrait concevoir ce chargeur de fichiers de configuration. Taylor dit qu'il aime simplement lancer un fichier texte vierge dans son éditeur, puis écrire comment il aimerait que les développeurs puissent interagir avec son code (l'API). Dans un contexte BDD, on appelle généralement cela le test du comportement externe de logiciels et d'outils tels que Behat, qui sont parfaits pour cela. Nous verrons cela dans un instant.

Premièrement, peut-être que Taylor prendra une décision concernant les fichiers de configuration. Comment devraient-ils travailler? Comme à Laravel, utilisons simplement des tableaux PHP simples. Un exemple de fichier de configuration pourrait ressembler à ceci:

# config.php  'UTC', );

Ensuite, comment le code utilisant ce fichier de configuration devrait-il fonctionner? Faisons cela à la manière de Taylor et écrivons simplement le code que nous souhaiterions avoir:

$ config = Config :: load ('config.php'); $ config-> get ('timezone'); // retourne 'UTC' $ config-> get ('timezone', 'CET'); // retourne 'CET' si 'timezone' n'est pas configuré $ config-> set ('timezone', 'GMT'); $ config-> get ('timezone'); // retourne 'GMT' 

Ok, alors ça a l'air bien. Nous avons d’abord un appel statique à un charge() fonction, suivie de trois cas d'utilisation: 

  1. Obtenir le "fuseau horaire" du fichier de configuration. 
  2. Obtenir une valeur par défaut si le "fuseau horaire" n'est pas encore configuré. 
  3. Changer une option de configuration en réglage à quelque chose d'autre. Nous allons décrire chacun de ces cas d'utilisation, ou des scénarios, avec Behat dans un court laps de temps.

Il est logique d'utiliser Behat pour ce genre de choses. Behat ne nous obligera pas à prendre de décision en matière de conception - nous avons phpspec pour cela. Nous allons simplement déplacer les exigences, que nous venons de décrire, dans un Behat fonctionnalité afin de nous assurer que nous faisons les choses correctement lorsque nous commençons à construire. Notre fonctionnalité behat servira de test d’acceptation de nos exigences pour ainsi dire.

Si vous regardez le code que nous avons écrit, l'appel statique est une autre raison d'utiliser Behat, au lieu de phpspec uniquement. Il n'est pas facile de tester des méthodes statiques, surtout si vous utilisez uniquement un outil tel que phpspec. Nous verrons comment nous pouvons nous y prendre quand nous aurons à la fois Behat et phpspec disponibles.

Installer

En supposant que vous utilisiez Composer, configurer Behat et phspec est un processus très simple en deux étapes..

Tout d'abord, vous avez besoin d'une base composer.json fichier. Celui-ci inclut Behat et phpspec, et utilise psr-4 pour charger automatiquement les classes:

"require-dev": "behat / behat": "~ 3.0", "phpspec / phpspec": "~ 2.0", "autoload": "psr-4": "": "src /"  

Courir compositeur installer chercher les dépendances.

phpspec n'a besoin d'aucune configuration pour s'exécuter, alors que Behat a besoin de vous pour exécuter la commande suivante afin de générer un échafaudage de base:

$ vendor / bin / behat --init

Voilà tout ce qu'il faut. Cela ne peut pas être votre excuse pour ne pas faire de BDD!

Planifier les fonctionnalités avec Behat

Alors, maintenant que nous sommes tous installés, nous sommes prêts à commencer à faire du BDD. Parce que BDD signifie installer et utiliser Behat et phpspec, à droite?

En ce qui me concerne, nous avons déjà commencé à faire du BDD. Nous avons efficacement décrit le comportement externe de notre logiciel. Nos "clients" dans cet exemple sont des développeurs, qui vont interagir avec notre code. Par "effectivement", je veux dire que nous avons décrit le comportement d'une manière qu'ils vont comprendre. Nous pourrions prendre le code que nous avons déjà décrit, le mettre dans un fichier README, et tout bon développeur PHP comprendrait son utilisation. C’est donc plutôt bon en réalité, mais j’ai deux choses importantes à noter à ce sujet. Tout d'abord, décrire le comportement d'un logiciel utilisant du code ne fonctionne que dans cet exemple car les "clients" sont des programmeurs. Normalement, nous testons quelque chose qui sera utilisé par des personnes "normales". Un langage humain est meilleur que PHP quand on veut communiquer avec des humains. Deuxièmement, pourquoi ne pas automatiser cela? Je ne vais pas discuter pourquoi cela pourrait être une bonne idée.

Cela étant dit, je pense que commencer à utiliser Behat serait une décision raisonnable.

En utilisant Behat, nous souhaitons décrire chacun des scénarios décrits ci-dessus. Nous ne souhaitons pas couvrir de manière exhaustive tous les cas d'utilisation du logiciel. Phpspec est disponible si cela est nécessaire pour corriger des bogues, etc. Je pense que de nombreux développeurs, y compris peut-être Taylor, ont le sentiment qu’ils doivent réfléchir à tout et décider de tout avant de pouvoir écrire des tests et des spécifications. C'est pourquoi ils choisissent de commencer sans BDD, car ils ne veulent pas tout décider à l'avance. Ce n’est pas le cas avec Behat, puisque nous décrivons le comportement et l’utilisation externes. Afin de pouvoir utiliser Behat pour décrire une fonctionnalité, nous n'avons pas besoin de décider plus que dans l'exemple ci-dessus avec l'utilisation d'un fichier texte brut. Il suffit de définir les exigences de la fonctionnalité - dans ce cas, l'API externe de la classe de chargeur de fichier de configuration.

Maintenant, prenons le code PHP ci-dessus et transformons-le en une fonctionnalité Behat, en utilisant la langue anglaise (en fait, en utilisant la langue Gherkin).

Faire un fichier dans le fonctionnalités/ répertoire, appelé config.feature, et complétez les scénarios suivants:

Fonctionnalité: Fichiers de configuration Pour configurer mon application En tant que développeur, je dois pouvoir stocker les options de configuration dans un fichier. Scénario: Obtention d'une option configurée Étant donné qu'il existe un fichier de configuration. L'option 'timezone' est configurée sur 'UTC'. Je charge le fichier de configuration. Ensuite, je devrais obtenir le code "UTC" en tant qu'option "Fuseau horaire" Scénario: Obtenir une option non configurée avec une valeur par défaut Étant donné qu'il existe un fichier de configuration Et l'option "fuseau horaire" n'est pas encore configurée Lorsque je charge la configuration Je devrais alors obtenir la valeur par défaut 'CET' comme option 'timezone' Scénario: Définition d'une option de configuration Etant donné qu'il existe un fichier de configuration Et l'option 'timezone' est configurée sur 'UTC' Lorsque je charge le fichier de configuration Et je règle ' Option de configuration 'timezone' à 'GMT' Ensuite, je devrais avoir l'option 'GMT' comme option 'timezone' 

Dans cette fonctionnalité, nous décrivons, de l'extérieur, comment un "développeur" pourrait stocker des options de configuration. Nous ne nous soucions pas du comportement interne - nous le ferons quand nous commencerons à utiliser phpspec. Tant que cette fonctionnalité passe au vert, nous ne nous soucions pas de ce qui se passe dans les coulisses.

Lançons Behat et voyons ce qu'il pense de notre fonctionnalité:

$ vendor / bin / behat --dry-run --append-snippets 

Avec cette commande, nous disons à Behat d'ajouter les définitions d'étape nécessaires à notre contexte de fonctionnalité. Je n’entrerai pas beaucoup dans les détails sur Behat, mais cela ajoute un tas de méthodes vides à notre FeatureContext classe qui correspond à nos étapes de fonctionnalité ci-dessus.

Par exemple, jetez un coup d’œil à la définition de l’étape que Behat a ajoutée pour le il y a un fichier de configuration étape que nous utilisons comme étape "donnée" dans les trois scénarios:

/ ** * @Given il existe un fichier de configuration * / public function thereIsAConfigurationFile () throw new PendingException ();  

Maintenant, tout ce que nous avons à faire est de renseigner du code pour décrire cette.

Écriture des définitions d'étape

Avant de commencer, j’ai deux remarques importantes sur les définitions d’étapes:

  1. Le but est de prouver que le comportement actuel n’est pas celui que nous souhaitons. Après cela, nous pouvons commencer à concevoir notre code, la plupart du temps en utilisant phpspec, afin de passer au vert.
  2. La mise en œuvre des définitions d'étape n'est pas importante - nous avons juste besoin de quelque chose qui fonctionne et qui atteint "1". Nous pouvons refactor plus tard.

Si vous courez fournisseur / bin / behat, vous verrez que tous les scénarios ont maintenant des étapes en attente.

Nous commençons par la première étape Étant donné qu'il y a un fichier de configuration. Nous allons utiliser une fixture du fichier de configuration pour pouvoir utiliser le static charge() méthode plus tard. Nous nous soucions de la statique charge() méthode parce qu'elle nous donne une belle API Config :: load (), un peu comme les façades de Laravel. Cette étape pourrait être mise en œuvre de nombreuses façons. Pour le moment, je pense que nous devrions simplement nous assurer que nous avons le fixture disponible et qu'il contient un tableau:

/ ** * @Given il existe un fichier de configuration * / public function thereIsAConfigurationFile () if (! File_exists ('fixtures / config.php')) émet une nouvelle exception ("Fichier 'fixtures / config.php' introuvable") ; $ config = include 'fixtures / config.php'; if (! is_array ($ config)) lève une nouvelle exception ("Le fichier 'fixtures / config.php' doit contenir un tableau");  

Nous allons passer au vert avec cette étape sans implémenter aucun code en dehors de la fabrication du fixture. Le but d'un Donné L’étape consiste à mettre le système dans un état connu. Dans ce cas, cela signifie s’assurer que nous avons un fichier de configuration.

Pour arriver à notre première étape verte, il nous suffit de créer le luminaire:

# fixtures / config.php 

Ensuite, nous avons un Et étape, qui dans ce cas est juste un alias pour Donné. Nous voulons nous assurer que le fichier de configuration contient une option pour le fuseau horaire. Encore une fois, ceci est uniquement lié à notre appareil, nous ne nous en soucions donc pas beaucoup. J'ai claqué le code (hackish) suivant pour accomplir ceci:

/ ** * @Given l'option: option est configurée pour: valeur * / fonction publique theOptionIsConfiguredTo ($ option, $ valeur) $ config = include 'fixtures / config.php'; if (! is_array ($ config)) $ config = []; $ config [$ option] = $ valeur; $ content = "

Le code ci-dessus n'est pas joli, mais il accomplit ce dont il a besoin. Cela nous permet de manipuler notre appareil depuis notre fonctionnalité. Si vous exécutez Behat, vous verrez qu'il a ajouté l'option "fuseau horaire" à la config.php fixation:

 'UTC', ); 

Il est maintenant temps d'introduire une partie du "code Taylor" original! La marche Quand je charge le fichier de configuration consistera en code que nous nous soucions réellement. Nous allons importer une partie du code du fichier texte brut précédent et nous assurer qu'il s'exécute:

/ ** * @Quand je charge le fichier de configuration * / public function iLoadTheConfigurationFile () $ this-> config = Config :: load ('fixtures / config.php'); // Taylor! 

Lancer Behat, bien sûr, cela échouera, car Config n'existe pas encore. Apportons phpspec à la rescousse!

Concevoir avec Phpspec

Lorsque nous lancerons Behat, nous aurons une erreur fatale:

Erreur PHP fatale: La classe 'Config' est introuvable… 

Heureusement, nous avons phpspec disponible, y compris ses générateurs de code géniaux:

$ vendor / bin / phpspec desc "Config" Spécification pour la configuration créée dans… /spec/ConfigSpec.php. $ vendor / bin / phpspec run --format = pretty Voulez-vous que je crée "Config" pour vous? y $ vendor / bin / phpspec run --format = pretty Config 10 ✔ est initialisable 1 spécification 1 exemples (1 transmis) 7ms 

Avec ces commandes, phpspec a créé les deux fichiers suivants pour nous:

spec / '- ConfigSpec.php src /' - Config.php

Cela nous a débarrassé de la première erreur fatale, mais Behat ne fonctionne toujours pas:

Erreur irrécupérable PHP: Appel de la méthode non définie Config :: load () dans… 

charge() va être une méthode statique et en tant que telle, n'est pas facile à spécifier avec phpspec. Pour deux raisons, tout va bien:

  1. Le comportement du charge() la méthode va être très simple. Si nous avons besoin de plus de complexité par la suite, nous pouvons extraire la logique de petites méthodes testables.
  2. Le comportement, pour l'instant, est assez bien couvert par Behat. Si la méthode ne charge pas correctement le fichier dans un tableau, Behat nous écrira.

C'est l'une de ces situations où beaucoup de développeurs vont se heurter au mur. Ils vont jeter phpspec et en conclure que ça craint et travaille contre eux. Mais voyez à quel point Behat et phpspec se complètent bien ici?

Au lieu d’essayer d’obtenir une couverture à 100% avec phpspec, implémentons un simple charge() fonctionner et être confiant qu’il est couvert par Behat:

paramètres = tableau ();  fonction statique publique load ($ path) $ config = new static (); if (file_exists ($ path)) $ config-> settings = include $ path; return $ config;  

Nous sommes assez confiants que nos options de configuration sont maintenant chargées. Sinon, le reste de nos étapes échouera et nous pourrons y revenir..

Construire la fonction avec itération

De retour au vert avec Behat et phpspec, nous pouvons maintenant regarder notre prochaine étape de fonctionnalité Alors je devrais obtenir 'UTC' comme option 'timezone'.

/ ** * Puis je devrais obtenir: valeur comme: option option * / fonction publique iShouldGetAsOption ($ value, $ option) $ actual = $ this-> config-> get ($ option); // Taylor! if (! strcmp ($ valeur, $ réelle) == 0) lève une nouvelle exception ("Attendu $ actuel à être '$ option'.");  

Dans cette étape, nous écrivons plus de code que nous souhaiterions avoir. En exécutant Behat cependant, nous verrons que nous n’avons pas obtenir() méthode disponible:

Erreur irrécupérable PHP: Appel de la méthode non définie Config :: get () dans… 

Il est temps de revenir à phpspec et de régler ce problème.

Tester les accesseurs et les mutateurs, les getters et les setters de AKA, est presque comme ce vieux dillemme de poule ou d’œuf. Comment pouvons-nous tester le obtenir() méthode si nous n'avons pas encore la ensemble() méthode et vice versa. Ce que j'ai tendance à faire, c'est simplement de les tester tous les deux à la fois. Cela signifie que nous allons réellement implémenter la fonctionnalité pour définir une option de configuration, même si nous n'avons pas encore atteint ce scénario..

L'exemple suivant devrait faire:

fonction it_gets_and_sets_a_configuration_option () $ this-> get ('foo') -> shouldReturn (null); $ this-> set ('foo', 'bar'); $ this-> get ('foo') -> shouldReturn ('bar');  

Premièrement, les générateurs phpspec nous aideront à démarrer:

$ vendor / bin / phpspec run --format = pretty Voulez-vous que je crée 'Config :: get ()' pour vous? y $ vendor / bin / phpspec run --format = pretty Voulez-vous que je crée "Config :: set ()" pour vous? y $ vendor / bin / phpspec run --format = Jolie La configuration 10 ✔ est initialisable 15 obtient et définit une option de configuration attendue, "bar", mais a la valeur null… 1 spéc. 2 exemples (1 transmis, 1 échoué) 9ms 

Revenons maintenant au vert:

fonction publique get ($ option) if (! isset ($ this-> settings [$ option])) return null; retourne $ this-> settings [$ option];  fonction publique définie ($ option, $ value) $ this-> settings [$ option] = $ value;  

Et voilà:

$ vendor / bin / phpspec run --format = joli Config 10 ✔ est initialisable 15 ✔ obtient et définit une option de configuration 1 specs 2 exemples (2 passés) 9ms 

Cela nous a pris un long chemin. En exécutant Behat, nous constatons que nous sommes bien engagés dans le deuxième scénario. Ensuite, nous devons implémenter la fonctionnalité d’option par défaut, car obtenir() est en train de revenir nul maintenant.

La première étape est similaire à celle décrite précédemment. Au lieu d’ajouter l’option au tableau, nous allons non fixé il:

/ ** * @Given l'option: l'option n'est pas encore configurée * / fonction publique theOptionIsNotYetConfigured ($ option) $ config = include 'fixtures / config.php'; if (! is_array ($ config)) $ config = []; unset ($ config [$ option]); $ content = "

Ce n'est pas joli Je connais! Nous pourrions sûrement le reformuler, puisque nous nous répétons, mais ce n'est pas le but de ce tutoriel..

La deuxième étape a aussi l’air familier et consiste principalement à copier et coller depuis:

/ ** * Ensuite, je devrais obtenir la valeur par défaut: valeur par défaut: option option * / fonction publique iShouldGetDefaultValueAsOption ($ default, $ option) $ actual = $ this-> config-> get ($ option, $ default); // Taylor! if (! strcmp ($ default, $ real)) == 0) lève une nouvelle exception ("Attendu $ actuel à être '$ default'.");  

obtenir() est de retour nul. Passons à phpspec et écrivons un exemple pour résoudre ceci:

fonction it_gets_a_default_value_when_option_is_not_set () $ this-> get ('foo', 'bar') -> shouldReturn ('bar'); $ this-> set ('foo', 'baz'); $ this-> get ('foo', 'bar') -> shouldReturn ('baz');  

Tout d'abord, nous vérifions que nous obtenons la valeur par défaut si "option" n'est pas encore configuré. Deuxièmement, nous nous assurons que l'option par défaut ne remplace pas une option configurée.

À première vue, phpspec peut sembler excessif dans ce cas, puisque nous testons déjà la même chose avec Behat. J'aime utiliser phpspec pour spécifier les cas extrêmes, ce qui est en quelque sorte implicite dans le scénario. Et aussi, les générateurs de code de phpspec sont vraiment géniaux. Je les utilise pour tout et je me trouve à travailler plus vite chaque fois que j'utilise phpspec.

Maintenant, phpspec confirme ce que Behat nous a déjà dit:

$ vendor / bin / phpspec run --format = pretty Config 10 ✔ est initialisable 15 ✔ obtient et définit une option de configuration 24 ✘ obtient une valeur par défaut lorsque l'option n'est pas définie "bar", mais a la valeur null… 1 spéc. 3 exemples ( 2 réussis, 1 échoué) 9ms 

Pour revenir au vert, nous allons ajouter un "retour anticipé" à la obtenir() méthode:

fonction publique get ($ option, $ defaultValue = null) if (! isset ($ this-> paramètres [$ option]) et! is_null ($ defaultValue)) return $ defaultValue; if (! isset ($ this-> settings [$ option])) renvoie null; retourne $ this-> settings [$ option];  

Nous voyons que phpspec est maintenant heureuse:

$ vendor / bin / phpspec run --format = joli Config 10 ✔ est initialisable 15 ✔ obtient et définit une option de configuration 24 ✔ obtient une valeur par défaut lorsque cette option n'est pas définie 1 spécifications 3 exemples (3 passés) 9ms 

Et Behat aussi, et nous aussi.

Nous avons terminé notre deuxième scénario et il en reste un. Pour le dernier scénario, il suffit d’écrire la définition de l’étape pour le Et je règle l'option de configuration 'timezone' sur 'GMT' étape:

/ ** * @Quand j'ai défini l'option: option de configuration sur: valeur * / fonction publique iSetTheConfigurationOptionTo ($ option, $ valeur) $ this-> config-> set ($ option, $ valeur); // Taylor!  

Depuis que nous avons déjà mis en œuvre le ensemble() méthode, cette étape est déjà verte:

$ vendor / bin / behat Fonctionnalité: Fichiers de configuration Pour configurer mon application En tant que développeur, je dois pouvoir stocker les options de configuration dans un fichier. Scénario: Obtenir une option configurée # features / config.feature: 6 Étant donné qu'il y a une configuration file # FeatureContext :: thereIsAConfigurationFile () Et l'option 'timezone' est configurée sur 'UTC' # FeatureContext :: theOptionIsConfiguredTo () Quand je charge le fichier de configuration # FeatureContext :: iLoadTheConfigurationFile (), je devrais obtenir le 'UTC' comme timez 'option # FeatureContext :: iShouldGetAsOption () Scénario: Obtention d'une option non configurée avec une valeur par défaut # features / config.feature: 12 Étant donné qu'il existe un fichier de configuration # FeatureContext :: thereIsAConfigurationFile () Et l'option' timezone 'n'est pas encore configuré # FeatureContext :: theOptionIsNotYetConfigured () Lorsque je charge le fichier de configuration # FeatureContext :: iLoadTheConfigurationFile () Ensuite, je devrais obtenir la valeur par défaut 'CET' comme option 'timezone' # FeatureContext :: iShould GetDefaultValueAsOption () Scénario: Définition d'une option de configuration # features / config.feature: 18 Étant donné qu'il existe un fichier de configuration # FeatureContext :: thereIsAConfigurationFile () et que l'option 'timezone' est configurée sur 'UTC' # FeatureContext :: theOptionIsConfiguredTo () Je charge le fichier de configuration # FeatureContext :: iLoadTheConfigurationFile () Et je règle l'option de configuration 'timezone' sur 'GMT' # FeatureContext :: iSetTheConfigurationOptionTo () Ensuite, je devrais avoir l'option 'GMT' comme 'timezone' # FeatureContext :: iShouldGetAsOption ( ) 3 scénarios (3 réussis) 13 étapes (13 réussies) 0m0.04s (8.92Mb) 

Emballer

Tout est beau et vert, alors finissons-en rapidement et voyons ce que nous avons accompli.

Nous avons décrit efficacement le comportement externe d'un chargeur de fichier de configuration, d'abord en utilisant l'approche de Taylor, puis en utilisant une approche BDD traditionnelle. Nous avons ensuite implémenté cette fonctionnalité en utilisant phpspec pour concevoir et décrire le comportement interne. L'exemple sur lequel nous travaillons est assez simple, mais nous avons couvert les bases. Si nous avons besoin de plus de complexité, nous pouvons simplement étendre ce que nous avons déjà. En utilisant BDD, nous avons au moins trois options:

  1. Si nous observons un bogue ou devons modifier certaines parties internes de notre logiciel, nous pouvons le décrire en utilisant phpspec. Ecrivez un exemple d'échec présentant le bogue et écrivez le code nécessaire pour accéder au vert.
  2. Si nous devons ajouter un nouveau cas d'utilisation à ce que nous avons, nous pouvons ajouter un scénario à  config.feature. Nous pouvons ensuite parcourir chaque étape de manière itérative, en utilisant Behat et phpspec.
  3. Si nous devons implémenter une nouvelle fonctionnalité, telle que la prise en charge des fichiers de configuration YAML, nous pouvons écrire une toute nouvelle fonctionnalité et recommencer à zéro, en utilisant l'approche que nous avons utilisée tout au long de ce tutoriel.

Avec cette configuration de base, nous n'avons aucune excuse pour ne pas écrire un test ou une spécification qui a échoué avant d'écrire notre code. Ce que nous avons construit est maintenant couvert par des tests, ce qui facilitera grandement son utilisation future. Ajoutez à cela que notre code est également entièrement documenté. Les cas d'utilisation prévus sont décrits dans un langage simple et le fonctionnement interne est décrit dans nos spécifications. Ces deux choses faciliteront la compréhension et l’utilisation de la base de code par les autres développeurs..

J'espère que ce tutoriel vous a aidé à mieux comprendre comment BDD peut être utilisé dans un contexte PHP, avec Behat et phpspec. Si vous avez des questions ou des commentaires, merci de les poster ci-dessous dans la section commentaires.

Merci d'avoir lu le long!