Rspec

Dans le monde de Ruby, il y a quelques librairies de test. Une des plus populaires et des plus utilisées est rspec. RSpec a une approche légèrement différente du test d’applications, puisqu’elle teste le comportement plutôt que des méthodes spécifiques. Je me suis dit que j’allais prendre un peu de temps pour montrer pourquoi rspec est tellement utile pour tester vos applications.

Les basiques

RSpec vous donne les moyens d’encapsuler ce que vous testez avec le bloc describe et son ami context. Dans le cas général d’un test unitaire, nous utilisons describe pour décrire le comportement d’une classe :

describe Hash do

end

On écrit les tests en utilisant le bloc it. Voici un exemple de comment vous pouvez écrire une spec pour la classe Hash :

describe Hash do
 it « should return a blank instance » do
   Hash.new.should == {}
 end
end

Ceci est la base de l’écriture d’exemples avec rspec. Vous pouvez essayer l’exemple précédent en installant rspec via gem install rspec et en mettant le code dans un fichier appelé hash_spec.rb. Tapez ensuite :

$ rspec hash_spec.rb

Vous devriez voir quelque chose qui ressemble à ceci :

.

Finished in 0.11021 seconds
1 example, 0 failures

Vous pouvez configurer l’état du test en utilisant les directives before et after. Cela s’appliquera à ce qui se trouve dans votre bloc describe :

describe Hash do
 before do
   @hash = Hash.new({:hello => ‘world’})
 end

 it « should return a blank instance » do
   Hash.new.should == {}
 end

 it « hash the correct information in a key » do
   @hash[:hello].should == ‘world’
 end
end

Le code ci-dessus créera la variable @hash avant que chaque test soit lancé. Il y a deux arguments pour before : all et each. En utilisant l’argument  all, le setup sera fait une fois avant tous les tests dans le bloc, et :each sera fait avant chaque test individuel. La directive after a les mêmes options et fonctionne de la même manière, mais après que les tests sont terminés. Ceci est particulièrement utile lors de la suppression de l’état antérieur des tests.

RSpec Idioms

On utilise généralement le mot-clé describe pour décrire les méthodes. Utiliser un “.” signifiera que vous testez une méthode de classe, et utiliser “#” signifiera qu’il s’agit une méthode d’instance. Voici à quoi cela peut ressembler pour une classe :  

describe MyClass do
 describe « .class_method_1 » do
 end

 describe « #instance_method_1 » do
 end
end

La méthode context fait la même chose en vous laissant contextualiser un bloc de vos tests. C’est extrêmement puissant pour l’état des tests quand vous ajoutez du code de configuration et de désassemblage plus compliqués pour réellement accéder à vos objets. Voyons ça dans un scénario qui s’applique à la vie réelle en créant une classe burger délicieuse.

Disons que dans notre classe Burger nous essayons de tester la méthode #apply_ketchup. Quelqu’un peut ne pas vouloir de ketchup dans son burger. Au lieu de les juger, nous écrirons un test pour la classe, pour ne pas appliquer le ketchup si quelqu’un n’en veut pas :

describe Burger do
 describe « #apply_ketchup » do
   context « with ketchup » do
     before do
       @burger = Burger.new(:ketchup => true)
       @burger.apply_ketchup
     end

     it « sets the ketchup flag to true » do
       @burger.has_ketchup_on_it?.should be_true
     end
   end

   context « without ketchup » do
     before do
       @burger = Burger.new(:ketchup => false)
       @burger.apply_ketchup
     end

     it « sets the ketchup flag to false » do
       @burger.has_ketchup_on_it?.should be_false
     end
   end
 end
end

Nettoyons un peu

Le schéma ci-dessus fonctionne mais peut devenir un peu fastidieux à répéter tout le temps. RSpec nous donne des méthodes helper pour le généraliser. On pourrait réécrire ce code en utilisant le mot-clé let pour faire la variable automatiquement. La variable serait alors créée la première fois qu’on y accède :

describe Burger do
 describe « #apply_ketchup » do
   context « with ketchup » do
     let(:burger) { Burger.new(:ketchup => true) }
     before  { burger.apply_ketchup }

     it « sets the ketchup flag to true » do
       burger.has_ketchup_on_it?.should be_true
     end
   end

   context « without ketchup » do
     let(:burger) { Burger.new(:ketchup => false) }
     before  { burger.apply_ketchup }

     it « sets the ketchup flag to false » do
       burger.has_ketchup_on_it?.should be_false
     end
   end
 end
end

Tout ceci fonctionne mais nous pouvons le nettoyer un peu plus en utilisant la méthode subject. Cette méthode dit à rspec que nous sommes en train de faire les tests. Nous allons combiner cela avec la méthode specify dans le prochain exemple. La méthode  specify est juste comme la méthode it sauf que la méthode specify prend le bloc de code comme description du test :

describe Burger do
 describe « #apply_ketchup » do
   subject { burger }
   before  { burger.apply_ketchup }

   context « with ketchup » do
     let(:burger) { Burger.new(:ketchup => true) }

     specify { subject.has_ketchup_on_it?.should be_true }
   end

   context « without ketchup » do
     let(:burger) { Burger.new(:ketchup => true) }

     specify { subject.has_ketchup_on_it?.should be_false }
   end
 end
end

Une chose intéressante à propos de rspec est que les matchers intégrés vous permettront de spécifier de manière déclarative des méthodes dans vos tests s’ils sont conformes à une certaine convention de nommage. RSpec va regarder si les méthodes qui sont nommées avec has et finissent par un point d’interrogation pour vous laisser faire du code de test déclaratif. Voici ce à quoi notre classe Burger va ressembler en utilisant cet idiome. Mettez le code suivant dans un fichier appelé burger_spec.rb et lancez-le :

class Burger
 attr_reader :options

 def initialize(options={})
   @options = options
 end

 def apply_ketchup
   @ketchup = @options[:ketchup]
 end

 def has_ketchup_on_it?
   @ketchup
 end
end


describe Burger do
 describe « #apply_ketchup » do
   subject { burger }
   before  { burger.apply_ketchup }

   context « with ketchup » do
     let(:burger) { Burger.new(:ketchup => true) }

     it { should have_ketchup_on_it }
   end

   context « without ketchup » do
     let(:burger) { Burger.new(:ketchup => false) }

     it { should_not have_ketchup_on_it }
   end
 end
end

Un burger a besoin de plus que du ketchup

Dans ce bref tutoriel, nous avons découvert rspec et créé une classe burger. Ensuite, nous avons refactorIn this brief tutorial we jumped in to rspec and created a burger class. Ensuite, nous avons un peu refactorisé nos tests pour les rendre plus idiomatiques. Ce avec quoi nous avons fini était plus facile à lire et plus rapide à lancer. Dans les prochains tutoriels de cette série, nous allons approfondir rspec, en voyant d’autres idiomes, des tests supplémentaires et l’écriture de nos propres comparateurs. Maintenant, en tout cas, je sais ce que je vais manger.

Laisser un commentaire

Choisissez une méthode de connexion pour poster votre commentaire:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion /  Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion /  Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion /  Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion /  Changer )

Connexion à %s