Cucumis sativus : Behaviour Driven Development avec Cucumber

Magazine
Marque
GNU/Linux Magazine
Numéro
128
Mois de parution
juin 2010


Résumé
Ah le cucumis sativus, cucurbitacée originaire de l´Himalaya, domestiquée en Inde pour la première fois il y a 3 millénaires, il en a fait du chemin. Désormais disponible partout de par le vaste monde civilisé (il paraît), il nous arrive incrusté de petits cailloux rouges.

Body

Cucumber [1][2], est un outil de BDD, ou Behaviour Driven Development (Développement guidé par le comportement). L´idée du BDD est de compléter le TDD (Test Driven Development) avec quelque chose qui rend plus de services. Non seulement on fait des tests, mais en plus, on le fait main dans la main avec le client.

J´ai personnellement eu quelques difficultés à m´y mettre, ne comprenant pas trop comment intégrer ce processus dans ma façon de travailler. Cependant, suite à une expérience récente, j'étais à la recherche d´une façon de modifier mon modus operandi afin d'éviter de perdre du temps et que mon activité soit plus rentable (comprendre « me fasse vivre »).

Cucumber est relativement connu, il est écrit en Ruby, marche avec RubyOnRails, a déjà plusieurs plugins (pour Nagios, par exemple, [4]) et un certain nombre d´outils pour Rails (Factory Girl [5], Machinist [6], ...). Bref, il semblait être un bon candidat pour résoudre mon problème.

Nous allons donc voir dans cet article comment faire une petite application Ruby (pas Ruby On Rails) en utilisant Cucumber. Nous couvrirons aussi rapidement ce qu´il faut faire pour intégrer Cucumber dans une application déjà existante.

J´ai aussi eu du mal à trouver une documentation claire sur le sujet. Je me suis souvent trouvé devant des instructions incomplètes. J´espère donc que cet article comblera ce problème, au moins pour les francophones.

Pour les allergiques à Ruby, il paraît que ça marche très bien avec d´autres langages comme Python, PHP, Java, ... Je dis « il paraît » parce que je ne l´ai pas vérifié personnellement. Consultez le site de Cucumber pour plus d´informations.

1. BDD ?

Dan North, un des auteurs de The Rspec book, décrit le BDD de la façon suivante :

1. Assez est assez : faire ce qu´il faut de préparation, analyse, ..., mais pas plus.

2. Livrer quelque chose qui a de la valeur : si vous n'êtes pas en train de faire quelque chose qui a de la valeur ou qui permettra d´en rajouter, alors arrêtez tout de suite.

3. Tout est comportement : que ce soit au niveau du code, de l´application ou au-delà, nous pouvons utiliser la même façon de penser et les mêmes constructions linguistiques pour décrire le comportement à tout niveau de granularité.

C´est un concept que j´apprécie particulièrement car j´ai récemment eu l´occasion de découvrir de façon douloureuse que j´avais codé trop et pas dans la bonne direction pour un projet. Que de temps perdu !

De façon plus large, le BDD fait partie des méthodes dites « Agile », de la seconde génération. Les méthodes Agile visent à améliorer le processus de création de logiciels en refondant les grandes lignes de celui-ci. Cela avait été résumé dans le Agile manifesto et notamment les « 4 valeurs » [10] :

  • Davantage l´interaction avec les personnes que les processus et les outils.
  • Davantage un produit opérationnel qu´une documentation pléthorique.
  • Davantage la collaboration avec le client que la négociation de contrat.
  • Davantage la réactivité face au changement que le suivi d´un plan.

Un exemple concret de l´utilisation de Cucumber est le suivant : élaborer dés le départ du projet la liste des fonctionnalités et leurs descriptions avec le client. Imaginez vous 2 minutes dans une salle de réunion comme nous les connaissons tous. Avec votre équipe, et le ou les clients en face. L´idée est de pousser le client à définir le plus possible ses besoins (avec votre aide) et de se servir de ce processus pour éclairer des zones d´ombres et comprendre ses besoins.

Pour les anglophones, une petite vidéo [3] illustre tout à fait ce processus dans les premières minutes. En assénant la question « pourquoi ? » un nombre suffisant de fois, le client détaillera le processus lié à une fonctionnalité demandée, et ce jusqu'à décrire son besoin initial (réduire les coûts, etc.).

Un exemple cité est le suivant (C : client, D : développeur) :

  • C : « Il nous faut une possibilité d´imprimer » ;
  • D : « Pourquoi ? » ;
  • C : « Parce qu´il nous faut pouvoir avoir les données sur une feuille » ;
  • D : « Pourquoi ? » ;
  • C : « Parce qu´on s´en sert pour rentrer les données dans ce poste et celui ci. »

Le lecteur malin comprendra vite que l´impression est donc remplaçable par un transfert de données entre les postes. (Sauvant ainsi un arbre et ses enfants du tronçonnage).

2. Concombre + yaourt

Passons aux choses concrètes et plongeons dans les hostilités. Pour commencer, il nous faut installer Cucumber et Rspec.

> sudo gem install cucumber

> sudo gem install rspec

Pffiou, après cet effort surhumain, créons l´arborescence qui va bien :

- some/where/

|

`-- lib/

`-- features/

|   `-- step_definitions/

|   `-- support/

|       `-- env.rb

`-- Rakefile           # optionnel

`-- script.rb # un .rb

- Le répertoire lib contiendra vos modules et classes.

- Le répertoire features contiendra tout ce qui concerne Cucumber. A sa racine se trouveront des .feature qui décriront le test, la feature voulue.

- Dans le répertoire step_definitions se trouvera le code des tests.

- Le répertoire support contient, lui, un fichier env.rb qui servira à initialiser l’environnement de test.

- Le Rakefile, lui, est optionnel, mais nous verrons quoi y mettre pour pouvoir utiliser Rake pour lancer les tests.

- script.rb sera un simple script Ruby. Nous partirons de l´idée que c’est notre application.

Il nous faut ensuite spécifier quelques prérequis pour Cucumber dans son fichier d´environnement :

# features/support/env.rb

require 'spec/expectations'

Cette bibliothèque correspond à des « attentes », méthodes qui nous serons utiles un peu plus loin et qui sont incluses dans la gem rspec installée précédemment.

2.1 Fonctionnement

Cucumber utilise deux fichiers pour fonctionner :

- une fonctionnalité, ou feature ;

- une liste d'étapes, ou steps.

Le premier permet de décrire en langage commun (pas celui des elfes donc) la fonctionnalité voulue à travers un scénario. On parle parfois d’«histoire ». Il utilise un langage particulier : Gherkin, qui est lisible par le commun des mortels.

Le second permet de faire un pont entre le précédent et le code réel.

2.2 Fonctionnalité

Notre exemple concernera des renards. Nous voulons avoir des renards. Avec du bacon. Pourquoi ? Parce que c´est sympa un renard.

Une fonctionnalité est stockée dans un fichier dont le nom se termine par l´extension « .feature ». Ils sont stockés dans le répertoire features/ et utilisent une syntaxe particulière :

# features/fox.feature

Feature: TITRE

DESCRIPTION

        Scenario: TITRE 2

                Given ...

                And ...

                When ...

Then ...

                And ...

Feature vous permet de définir le début de la fonctionnalité, et son titre, suivi d´une brève description. Puis Scenario permet de donner un titre au scénario décrit. Ensuite vient une description en anglais en utilisant les mots-clés Given, When et Then.

  • Given (« Soit ») : permet d´indiquer quelque chose qui est connu comme vrai dans le cadre de ce scénario : une « vérité générale ». Ce ne doit pas être une pré-condition, il faut que ce soit quelque chose qui fournit un contexte au scénario.
  • When (« Quand ») : décrit l'événement qui a lieu dans le scénario (« Quand je donne un nom », « Quand je prends le train », ...). On préférera donc n´avoir qu’un événement par scénario.
  • Then (« Alors ») : décrit les conséquences de l'événement, la situation que l´on doit trouver à la suite de celui-ci.

Nous pouvons aussi utiliser le And pour spécifier une condition supplémentaire, point supplémentaire, ou une conséquence supplémentaire de l'événement. Que les non anglophones se rassurent : Cucumber permet aussi de décrire les fonctionnalités en anglais, passez au paragraphe « Molière serait content » en fin de cette section, pour avoir les clés pour suivre l´article.

Rédigeons donc une fonctionnalité : nous voulons prendre un renard et pouvoir lui donner un nom.

# features/fox.feature

Feature: Give a name to a fox

        In order to find our fox we want to give him a name

        Scenario: Give a name

                Given a fox

                And a "name"

                When I set the name to the fox

                Then the fox should have a name

Nous venons de décrire un processus relativement simple qui correspond à ce que l´on veut faire. C´est parfaitement compréhensible, en anglais ou en français, par des personnes ayant ou non des connaissances techniques.

Une fois une fonctionnalité écrite, on peut utiliser la commande cucumber en lui passant le fichier .feature en paramètre :

> cucumber features/fox.feature

Feature: Give a name to a fox

        In order to find our fox we want to give him a name

  Scenario: Give a name             # features/fox.feature:4

    Given a fox                     # features/fox.feature:5

    And a "name"                     # features/fox.feature:6

    When I set the name to the fox # features/fox.feature:7

    Then the fox should have a name # features/fox.feature:8

1 scenario (1 undefined)

4 steps (4 undefined)

0m0.009s

You can implement step definitions for undefined steps with these snippets:

Given /^a fox$/ do

  pending # express the regexp above with the code you wish you had

end

Given /^a "([^\"]*)"$/ do |arg1|

  pending # express the regexp above with the code you wish you had

end

When /^I set the name to the fox$/ do

  pending # express the regexp above with the code you wish you had

end

Then /^the fox should have a name$/ do

  pending # express the regexp above with the code you wish you had

end

Nous récupérons donc : une sortie directe de notre scénario, avec toutes les lignes en jaune. Le statut du scénario (undefined), et le statut des 4 steps (undefined). Le tout suivi de snippets, que nous pourrions utiliser dans un « step definitions ».

2.3 Définitions des étapes

Nous passons donc à l'étape suivante : écrire le code qui va réaliser ces tests : les step definitions, ou « définitions d'étapes ». Nous pouvons donc copier/coller le code précédemment proposé par Cucumber dans le fichier features/step_definitions/fox_step.rb :

# features/step_definitions/fox_step.rb

Given /^a fox$/ do

  pending # express the regexp above with the code you wish you had

end

Given /^a "([^\"]*)"$/ do |arg1|

  pending # express the regexp above with the code you wish you had

end

When /^I set the name to the fox$/ do

  pending # express the regexp above with the code you wish you had

end

Then /^the fox should have a name$/ do

  pending # express the regexp above with the code you wish you had

end

Le nom du fichier n’est évidemment pas anodin puisqu’il correspond au basename du fichier fox.feature auquel on a ajouté le suffixe _step.rb. C´est ainsi que Cucumber fait le lien entre les deux. C´est un fichier Ruby avec une syntaxe un peu particulière : nous remarquons de belles regexp et le mot-clé pending, qui permet à Cucumber de voir que le step n´est pas encore écrit. Nous allons donc essayer d'écrire ces steps, en commençant par le premier (logique, non ?) :

Given /^a fox$/ do

        @fox = Fox.new

end

Cette étape correspond à « Soit un renard ». Il nous faut donc un renard. Nous créons donc un objet, instance de la classe Fox (renard). Puis nous exécutons à nouveau le scénario :

> cucumber features/fox.feature

Feature: Give a name to a fox

        In order to find our fox we want to give him a name

  Scenario: Give a name             # features/fox.feature:4

    Given a fox                     # features/step_definitions/fox_step.rb:1

      uninitialized constant Fox (NameError)

      ./features/step_definitions/fox_step.rb:2:in `/^a fox$/'

      features/fox.feature:5:in `Given a fox'

    And a "name"                    # features/step_definitions/fox_step.rb:5

    When I set the name to the fox # features/step_definitions/fox_step.rb:9

    Then the fox should have a name # features/step_definitions/fox_step.rb:13

Failing Scenarios:

cucumber features/fox.feature:4 # Scenario: Give a name

1 scenario (1 failed)

4 steps (1 failed, 3 skipped)

0m0.009s

Les lignes jaunes ont disparu, et nous avons désormais du rouge et du bleu. Le scénario est déclaré comme « failed » (« échoué »), 3 étapes sont déclarées comme « ignorées » et une étape est déclarée comme « échouée ».

Le problème est que Cucumber ne trouve pas la constante Fox. C´est logique, puisque nous n´avons pas encore défini de classe Fox. Continuons à rédiger les étapes :

Given /^a "([^\"]*)"$/ do |name|

  @name = name

end

When /^I set the name to the fox$/ do

  @fox.name = @name

end

Then /^the fox should have a name$/ do

@fox.name.should_not == nil

end

Rien de bien sorcier, mais le premier step est particulièrement intéressant, puisque nous utilisons un groupe dans l´expression régulière pour récupérer une variable et la passer au code.

A nouveau, nous ne faisons rien de compliqué : nous ne faisons qu'écrire en Ruby ce qui est décrit en anglais : - « Soit un nom » : en extrayant name via la regexp, nous l´assignons à la variable @name. – « Quand je donne un nom au renard » : nous donnons le nom au renard en assignant l´attribut name (nom) de l´objet @fox (renard), la valeur de la variable @name. – « Alors le renard devrait avoir un nom » : nous testons alors que @fox.name existe bel et bien. Plus exactement, nous vérifions qu´il n´est pas égal à nil. Notons au passage l’utilisation de la méthode should et de la lisibilité que cela donne au code.

Si nous réexécutons les tests, rien n’a changé. C’est tout à fait normal. Nous avons décrit la fonctionnalité voulue, nous avons écrit les tests pour vérifier si cette fonctionnalité est implémentée, mais nous n´avons pas encore implémenté celle-ci. Il nous faut donc passer à cette étape-là.

2.4 Du code dudju, du code !

Créons donc un fichier lib/fox.rb 

class Fox

end

En exécutant Cucumber à nouveau, « paf », nous obtenons toujours la même erreur. Cette fois-ci, le problème se situe dans le fait que Cucumber ne sait pas où aller chercher nos classes et nous envoie donc balader. Ce problème n´existe pas dans le cas de l´utilisation de Cucumber avec Rails, mais existe bel et bien dans le cas qui nous intéresse présentement.

Pour résoudre ce problème, il nous faut éditer le fichier features/support/env.rb et lui ajouter un path de chargement en la personne de notre répertoire lib/ qui contient notre classe. Enfin, nous devons ajouter un petit require pour inclure notre classe :

# features/support/env.rb

# cucumber own requires

require 'spec/expectations'

# your app requires

$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')

require 'lib/fox'

Exécutons à nouveau cucumber :

> cucumber features/fox.feature

Feature: Give a name to a fox

        In order to find our fox we want to give him a name

  Scenario: Give a name             # features/fox.feature:4

    Given a fox                     # features/step_definitions/fox_step.rb:1

    And a "name"                    # features/step_definitions/fox_step.rb:5

    When I set the name to the fox # features/step_definitions/fox_step.rb:9

      undefined method `name=' for #<Fox:0x101520768> (NoMethodError)

      ./features/step_definitions/fox_step.rb:10:in `/^I set the name to the fox$/'

      features/fox.feature:7:in `When I set the name to the fox'

    Then the fox should have a name # features/step_definitions/fox_step.rb:13

Failing Scenarios:

cucumber features/fox.feature:4 # Scenario: Give a name

1 scenario (1 failed)

4 steps (1 failed, 1 skipped, 2 passed)

0m0.023s

Cette fois-ci, deux steps sont passés (passed), un a échoué (et continue de cracher ses tripes sur la plage), et le dernier a été ignoré.

Le step qui a échoué nous indique qu´il voudrait bien une méthode name= pour l´objet de classe Fox. Nous allons donc écrire cette méthode :

class Fox

  def name=(name)

    @name = name

  end

end

#

# executons cucumber

> cucumber features/fox.feature

...

        Then the fox should have a name # features/step_definitions/fox_step.rb:13

              undefined method `name' for #<Fox:0x101520510 @name="name"> (NoMethodError)

              ./features/step_definitions/fox_step.rb:14:in `/^the fox should have a name$/'

              features/fox.feature:8:in `Then the fox should have a name'

        Failing Scenarios:

        cucumber features/fox.feature:4 # Scenario: Give a name

1 scenario (1 failed)

4 steps (1 failed, 3 passed)

0m0.012s

Une étape de plus de passée, mais il en reste encore une, et il manque pour cela une méthode name. Ajoutons donc celle-ci à notre classe et repassons un coup de cucumber :

def name

  return @name

end

#

# executons cucumber

> cucumber features/fox.feature

...

1 scenario (1 passed)

4 steps (4 passed)

0m0.010s

Si c´est tout vert, c´est que c´est bon.

Le but de base est atteint : nous avons écrit une fonctionnalité, des étapes, et le code qu´il fallait pour que celles-ci passent au vert. Cependant, on peut probablement faire mieux et l'étape qui suit est donc celle de la refactorisation (comme en maths, oui).

2.5 Refactor

Le code n'étant pas très « rubiesque », faisons un peu mieux en remplaçant les deux méthodes par un simple attr_accessor :

class Fox

  attr_accessor :name

end

#

# executons cucumber

> cucumber features/fox.feature

...

1 scenario (1 passed)

4 steps (4 passed)

0m0.015s

Nous venons de terminer une itération classique de BDD : écriture des scénarios, des étapes, du code, et refactorisation.

2.6 Un peu de poivre

Juste pour s´amuser, nous pourrions changer le scénario afin de voir un peu plus ce qui est faisable :

Feature: Give a name to a fox

        In order to find our fox we want to give him a name

        Scenario: Give a name

                Given a fox

                And a name : "bob"

                When I set the name to the fox

                Then the fox should be called "bob"

Nous avons ajouté ici le nom "bob", il serait en effet intéressant de passer un vrai nom dans le scénario et de tester l´objet avec. Nous devons changer les étapes en conséquence :

Given /^a fox$/ do

        @fox = Fox.new

end

Given /^a name : "([^\"]*)"$/ do |name|

  @name = name

end

When /^I set the name to the fox$/ do

  @fox.name = @name

end

Then /^the fox should be called "([^\"]*)"$/ do |name|

  @fox.name.should == name

end

Nous remarquons l´utilisation d´un groupe à nouveau. Si nous exécutons Cucumber à nouveau, nous devrions obtenir du vert tout vert.

2.7 Bonus track

Pour simplifier notre vie, nous pouvons utiliser Rake pour lancer Cucumber. Un Rakefile pour faire cela peut se présenter comme suit :

task :cucumber do

  $:.unshift(File.dirname(__FILE__) + '../lib')

  begin

    require 'cucumber/rake/task'

    Cucumber::Rake::Task.new(:features)

  rescue LoadError

    puts "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"

  end

  Cucumber::Rake::Task.new do |t|

    t.cucumber_opts = %w{--format pretty}

end

end

Pour tester tous les scénarios, il nous suffira alors de taper :

> rake cucumber

Nous pouvons aussi simplement utiliser la commande cucumber à la racine de notre projet.

2.8 Molière serait content

Puisque Cucumber se veut lisible par le client, il supporte plusieurs langues pour écrire les features et les steps. On peut donc très bien utiliser du français, ou même du LOLCAT (si si) :

# features/renard.feature

# language: fr

Fonctionnalité: TITRE

        DESCRIPTION

        Scénario: TITRE 2

                Soit ...

                Et ...

                Lorsque ...

                Alors ...

                Et ...

Vous pouvez utiliser la commande cucumber --i18n help pour avoir la liste des langues supportées et cucumber --i18n fr pour connaître la correspondance exacte des mots-clés en français.

Voici une version française de ce que nous venons de faire en anglais :

# renard.feature

# language: fr

Fonctionnalité: Donner un nom au renard

        Afin de retrouver notre renard nous voulons lui donner un nom

        Scénario: Donner un nom

                Soit un renard

                Et un nom : "bob"

                Lorsque je donne le nom au renard

                Alors le renard devrait s'appeller "bob"

>

# renard_step.rb

# language: fr

Soit %r{^un renard$} do

  @fox = Fox.new

end

Soit %r{^un nom : "([^\"]*)"$} do |nom|

  @name = nom

end

Lorsque %r{^je donne le nom au renard$} do

  @fox.name = @name

end

Alors %r{^le renard devrait s'appeller "([^\"]*)"$} do |nom|

  @fox.name.should == nom

end

La syntaxe des regexp est ici différente, mais seulement par goût personnel, et revient exactement à la même chose. Si nous lançons la tâche rake :

> rake cucumber

...

Feature: Give a name to a fox

        In order to find our fox we want to give him a name

  Scenario: Give a name                 # features/fox.feature:4

...

# language: fr

Fonctionnalité: Donner un nom au renard

        Afin de retrouver notre renard nous voulons lui donner un nom

  Scénario: Donner un nom                   # features/renard.feature:5

...

2 scenarios (2 passed)

8 steps (8 passed)

0m0.005s

Molière serait donc content de voir sa langue si bien utilisée.

2.9 Pour finir

Nous avons donc vu un rapide aperçu de Cucumber, comment l’utiliser et comment baser un processus de développement dessus. En somme, il s´agit de suivre les étapes suivantes :

1. Décrire l´application en termes de features.

2. Ecrire les étapes de chaque feature.

3. Lancer Cucumber et voir les tests échouer.

4. Ecrire le code de façon à ce qu’une feature passe au vert.

5. Lancer Cucumber.

6. Si des steps ne sont pas verts, retourner en 4.

7. Refactoriser le code.

Comme le souligne un article (7, en anglais), Cucumber ne remplace pas non plus des tests unitaires. Et cet article recommande d’utiliser le processus suivant :

  1. Décrire l´application en termes de features.
  2. Ecrire les étapes de chaque feature.
  3. Lancer Cucumber et voir les tests échouer.
  4. Ecrire les tests unitaires, les voir échouer, écrire le code nécessaire à leur passage.
  5. Ecrire les tests fonctionnels, les voir échouer, écrire le code nécessaire à leur passage.
  6. Lancer Cucumber, si certains steps ne sont toujours pas en vert, retourner en 4.
  7. Refactoriser le code.

A vous de voir.

3. Concombre + sauce toute prête

Intégrer Cucumber à une application existante est relativement simple, bien qu’il faille tomber sur les bonnes informations.

3.1 Créer l´arborescence

Il nous suffit de créer l´arborescence vue précédemment :

- some/where/

|

`-- features/

|   `-- step_definitions/

|   `-- support/

|       `-- env.rb

Attention, cela n´est que pour une application Ruby classique, pas une application RubyOnRails, pour celle-ci, il y a des choses particulières à mettre en œuvre. Nous ne les abordons pas dans cet article, hélas, mais elles sont décrites dans plusieurs documentations.

3.2 Rake

Pour plus de confort, je vous conseille d´intégrer la tâche rake précédemment décrite dans votre Rakefile.

3.3 Env

Le fichier env.rb devra contenir le contenu suivant :

# features/support/env.rb

require 'spec/expectations'

# changer LIB par le dossier contenant vos classes et modules

$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../LIB')

## requires

Complétez cette base avec les requires correspondant à vos classes.

Conclusion

Nous avons donc couvert un terrain relativement large de façon très rapide, et Cucumber offre bien d´autres possibilités :

  • organiser les features par thèmes dans des sous-dossiers ;
  • utiliser des tags ;
  • utiliser des tableaux dans les scénarios ;
  • intégrer des outils comme Shoulda, Machinist, Factory Girl ... ;
  • ...

Bref, il y a encore de quoi lire et apprendre. Je vous conseille donc de vous diriger vers le site de Cucumber et de creuser la question, lisez les docs, les blogs, etc.

Personnellement, j´ai beaucoup aimé l’idée globale et le fait que cela peut nous permette de réduire la quantité de code à écrire (et donc à maintenir). Un problème de taille à l´adoption d´un tel outil (ou d’un tel processus de développement) peut être notre incapacité à nous remettre en question (je suis passé par là), nous devons nous demander si notre processus est vraiment le bon ou pas, ou s’il peut être amélioré. C’est là le but des méthodes Agile (à mon humble avis), et j´ai appris la leçon d´une façon un peu moche. Donc : toujours rester ouvert à la nouveauté, au changement.

Comme certains lutins le soulignaient récemment, Ruby semble prendre de plus en plus pied dans le milieu de l´administration système, comme Perl a pu le faire par le passé. Il est vrai que, puisqu’il est largement inspiré de Perl, mais avec un aspect objet beaucoup plus -ahem- moderne (?), il a beaucoup pour plaire.

J´espère que ça vous sera utile.

Liens

[1] Cucumber @ GitHub : http://github.com/aslakhellesoy/cucumber

[2] Cucumber : http://cukes.info/

[3] Vidéo de présentation : http://mwrc2009.confreaks.com/14-mar-2009-15-00-bdd-with-cucumber-ben-mabey.html

[4] Cucumber Nagios : http://auxesis.github.com/cucumber-nagios/

[5] Factory Girl : http://github.com/thoughtbot/factory_girl

[6] Machinist : http://github.com/notahat/machinist

[7] « Cucumber déchire mais ne remplace pas les tests unitaires » : http://www.pathf.com/blogs/2009/06/cucumber-rocks-but-its-not-a-replacement-for-unit-tests/

[8] 15 Cucumber Tips : http://www.engineyard.com/blog/2009/15-expert-tips-for-using-cucumber/ (orienté Rails)

[9] Code d´exemple de l´article : http://github.com/mcansky/Article-Cucumis-sativus (sous licence MIT).

[10] Agile Manifesto sur Wikipédia : http://fr.wikipedia.org/wiki/Manifeste_agile




Article rédigé par

Par le(s) même(s) auteur(s)

Protobuf avec Ruby : je suis tombé sur un buffer !

Magazine
Marque
GNU/Linux Magazine
Numéro
256
Mois de parution
mars 2022
Spécialité(s)
Résumé

Opter pour un mécanisme extensible de sérialisation et désérialisation de données peut grandement vous simplifier la vie et celle de votre équipe. En particulier lors de la conception, puis de la mise en œuvre d'une nouvelle API. Voyons comment Protobuf va éclairer votre journée de développeur Ruby...

Les derniers articles Premiums

Les derniers articles Premium

La place de l’Intelligence Artificielle dans les entreprises

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

L’intelligence artificielle est en train de redéfinir le paysage professionnel. De l’automatisation des tâches répétitives à la cybersécurité, en passant par l’analyse des données, l’IA s’immisce dans tous les aspects de l’entreprise moderne. Toutefois, cette révolution technologique soulève des questions éthiques et sociétales, notamment sur l’avenir des emplois. Cet article se penche sur l’évolution de l’IA, ses applications variées, et les enjeux qu’elle engendre dans le monde du travail.

Petit guide d’outils open source pour le télétravail

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Ah le Covid ! Si en cette période de nombreux cas resurgissent, ce n’est rien comparé aux vagues que nous avons connues en 2020 et 2021. Ce fléau a contraint une large partie de la population à faire ce que tout le monde connaît sous le nom de télétravail. Nous avons dû changer nos habitudes et avons dû apprendre à utiliser de nombreux outils collaboratifs, de visioconférence, etc., dont tout le monde n’était pas habitué. Dans cet article, nous passons en revue quelques outils open source utiles pour le travail à la maison. En effet, pour les adeptes du costume en haut et du pyjama en bas, la communauté open source s’est démenée pour proposer des alternatives aux outils propriétaires et payants.

Sécurisez vos applications web : comment Symfony vous protège des menaces courantes

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Les frameworks tels que Symfony ont bouleversé le développement web en apportant une structure solide et des outils performants. Malgré ces qualités, nous pouvons découvrir d’innombrables vulnérabilités. Cet article met le doigt sur les failles de sécurité les plus fréquentes qui affectent même les environnements les plus robustes. De l’injection de requêtes à distance à l’exécution de scripts malveillants, découvrez comment ces failles peuvent mettre en péril vos applications et, surtout, comment vous en prémunir.

Bash des temps modernes

Magazine
Marque
Contenu Premium
Spécialité(s)
Résumé

Les scripts Shell, et Bash spécifiquement, demeurent un standard, de facto, de notre industrie. Ils forment un composant primordial de toute distribution Linux, mais c’est aussi un outil de prédilection pour implémenter de nombreuses tâches d’automatisation, en particulier dans le « Cloud », par eux-mêmes ou conjointement à des solutions telles que Ansible. Pour toutes ces raisons et bien d’autres encore, savoir les concevoir de manière robuste et idempotente est crucial.

Les listes de lecture

9 article(s) - ajoutée le 01/07/2020
Vous désirez apprendre le langage Python, mais ne savez pas trop par où commencer ? Cette liste de lecture vous permettra de faire vos premiers pas en découvrant l'écosystème de Python et en écrivant de petits scripts.
11 article(s) - ajoutée le 01/07/2020
La base de tout programme effectuant une tâche un tant soit peu complexe est un algorithme, une méthode permettant de manipuler des données pour obtenir un résultat attendu. Dans cette liste, vous pourrez découvrir quelques spécimens d'algorithmes.
10 article(s) - ajoutée le 01/07/2020
À quoi bon se targuer de posséder des pétaoctets de données si l'on est incapable d'analyser ces dernières ? Cette liste vous aidera à "faire parler" vos données.
Voir les 65 listes de lecture

Abonnez-vous maintenant

et profitez de tous les contenus en illimité

Je découvre les offres

Déjà abonné ? Connectez-vous