Ruby for Newbies Test avec Rspec

Ruby est l’un des langages les plus utilisés sur le Web. Nous organisons ici une session sur Nettuts + qui vous présentera Ruby, ainsi que les formidables cadres et outils associés au développement de Ruby. Dans cet épisode, vous apprendrez à tester votre code Ruby avec Rspec, l'une des meilleures bibliothèques de test du marché..


Préférer un screencast?

Semble familier?

Si vous avez lu mon récent tutoriel sur JasmineJS, vous remarquerez probablement plusieurs similitudes dans Rspec. En fait, les similitudes sont dans Jasmine: Jasmine a été créé avec Rspec à l’esprit. Nous allons voir comment utiliser Rspec pour effectuer des TDD en Ruby. Dans ce tutoriel, nous allons créer des classes Ruby artificielles pour nous familiariser avec la syntaxe Rspec. Cependant, le prochain? Ruby for Newbies? L'épisode comportera-t-il l'utilisation de Rspec conjointement avec d'autres bibliothèques pour tester les applications Web? alors restez à l'écoute!


Mise en place

C'est assez facile d'installer Rspec. Ouvrez cette ligne de commande et lancez ceci:

gem installer rspec

C'est facile.

Maintenant, mettons en place un petit projet. Nous allons créer deux classes: Livre et Bibliothèque. Notre Livre les objets ne feront que stocker un titre, un auteur et une catégorie. Notre Bibliothèque object stockera une liste de livres, les enregistrera dans un fichier et nous permettra de les récupérer par catégorie.

Voici à quoi devrait ressembler votre répertoire de projet:

Nous mettons les spécifications (ou spécifications) dans un spec dossier; nous avons un fichier de spécification pour chaque classe. Remarquez le spec_helper.rb fichier. Pour que nos spécifications soient exécutées, nous devons exiger les classes Ruby que nous testons. C'est ce que nous faisons à l'intérieur du spec_helper fichier:

require_relative '? / bibliothèque 'require_relative'? / book 'require' yaml '

(Avez-vous rencontré require_relative encore? Non? bien, require_relative est juste comme exiger, sauf qu'au lieu de chercher votre chemin Ruby, il cherche relatif dans le répertoire actuel.)

Vous ne connaissez peut-être pas le module YAML; YAML est une base de données texte simple que nous utiliserons pour stocker des données. Vous verrez comment cela fonctionne et nous en reparlerons plus tard..

Alors, maintenant que nous sommes tous prêts, commençons par casser quelques spécifications!


le Livre Classe

Commençons par les tests pour le Livre classe.

nécessite 'spec_helper' décrire Book do end

Voici comment on commence: avec un décrire bloc. Notre paramètre à décrire explique ce que nous testons: cela pourrait être une chaîne, mais dans notre cas, nous utilisons le nom de la classe.

Alors qu'est-ce qu'on va mettre à l'intérieur de cette décrire bloc?

before: each do @book = Book.new "Titre", "Auteur",: catégorie fin

Nous allons commencer par faire un appel à avant; on passe le symbole :chaque de spécifier que nous voulons que ce code soit exécuté avant chaque test (nous pourrions aussi le faire :tout exécuter une fois avant tous les tests). Que faisons-nous exactement avant chaque test? Nous créons une instance de Livre. Remarquez comment nous en faisons une variable d'instance, en ajoutant le nom de la variable avec @. Nous devons faire cela pour que notre variable soit accessible depuis nos tests. Sinon, nous allons simplement obtenir une variable locale qui ne fonctionne que dans le avant bloc? ce qui n'est pas bon du tout.

Passer à autre chose,

describe "#new" do it "prend trois paramètres et retourne un objet Book" do @ book.should be_an_instance_of Book end

Voici notre premier test. Nous utilisons un imbriqué décrire bloquer ici pour dire que nous décrivons les actions d'une méthode spécifique. Vous remarquerez que j'ai utilisé la chaîne? #New ?; c'est une convention en ruby ​​de parler de se référer à des méthodes d'instance comme celle-ci: NomClasse # NomMéthode Puisque nous avons le nom de la classe dans notre niveau supérieur décrire, nous mettons juste le nom de la méthode ici.

Notre test confirme simplement que nous sommes en fait un objet Book.

Notez la grammaire que nous utilisons ici: object.should do_chose. Quatre-vingt-dix-neuf pour cent de vos tests prendront cette forme: vous avez un objet et vous commencez par appeler devrait ou ne devrait pas sur l'objet. Ensuite, vous transmettez à cet objet l'appel d'une autre fonction. Dans ce cas c'est be_an_instance_of (qui prend Livre comme paramètre unique). Au total, cela fait un test parfaitement lisible. C'est très clair que @livre devrait être une instance de la classe Livre. Alors courons-le.

Ouvrez votre terminal, CD dans le répertoire du projet et lancez spécification de rspec. le spec est le dossier dans lequel rspec va trouver les tests. Vous devriez voir la sortie dire quelque chose à propos de? Constante non initialisée Object :: Book ?; cela signifie simplement qu'il n'y a pas Livre classe. Corrigeons ça.

Selon TDD, nous souhaitons uniquement écrire suffisamment de code pour résoudre ce problème. dans le book.rb fichier, ce serait ceci:

classe livre fin

Relancez le test (spécification de rspec), et vous constaterez que ça passe très bien. Nous n'avons pas de initialiser méthode, appelant ainsi Ruby # nouveau n'a aucun effet pour l'instant. Mais nous pouvons créer Livre objets (bien que creux.) Normalement, nous suivrions ce processus tout au long de notre développement: écrivez un test (ou quelques tests connexes), regardez-le échouer, faites-le passer, refacturez, répétez. Cependant, pour ce tutoriel, je vais simplement vous montrer les tests et le code, et nous en discuterons.

Donc, plus de tests pour Livre:

decrire "#title" do it "renvoie le titre correct" do @ book.title.should eql "Title" fin et décris "#author" do it "renvoie le bon auteur" do @ book.author.should eql "Author" end end describe "#category" do it "renvoie la catégorie correcte" do @ book.category.should eql: category end end

Il devrait être très facile pour vous. Mais remarquez comment nous comparons dans le test: avec eql. Il existe trois façons de tester l’égalité avec Rspec: en utilisant l’opérateur == ou la méthode eql les deux reviennent vrai si les deux objets ont le même contenu. Par exemple, les deux sont des chaînes ou des symboles qui disent la même chose. Puis il y a égal, qui ne renvoie vrai que dans les deux objets sont vraiment et véritablement égaux, ce qui signifie qu'ils sont le même objet en mémoire. Dans notre cas, eql (ou ==) est ce que nous voulons.

Ceux-ci vont échouer, alors voici le code pour Livre pour les faire passer:

class Book attr_accessor: title,: author,: category def initialise le titre, author, category @title = title @author = author @category = fin de la catégorie

Passons à Bibliothèque!


Spécifier le Bibliothèque classe

Celui-ci sera un peu plus compliqué. Commençons par ceci:

require 'spec_helper' décrire "un objet de bibliothèque", faire avant: tout faire lib_obj = [Book.new ("JavaScript: les bonnes parties", "Douglas Crockford",: développement), Book.new ("Designing with Web Standards", " Jeffrey Zeldman ", design, Book.new (" Ne me faites pas penser "," Steve Krug ",: convivialité), Book.new (" JavaScript Patterns "," Stoyan Stefanov ",: développement), Book. new ("Responsive Web Design", "Ethan Marcotte",: design)] File.open "books.yml", "w" do | f | f.write YAML :: dump lib_obj end end avant: chaque do @lib = Library.new "books.yml" end end

Ceci est tout mis en place: nous utilisons deux avant blocs: un pour :chaque et un pour :tout. dans le avant tout bloc, nous créons un tableau de livres. Ensuite, nous ouvrons le fichier? Books.yml? (en? w? rite mode) et utiliser YAML vider le tableau dans le fichier.

Petit tour d'horizon des lapins pour expliquer un peu mieux YAML: YAML est, selon le site, un standard de sérialisation des données convivial pour tous les langages de programmation. C'est comme une base de données textuelle, un peu comme JSON. Nous importons YAML dans notre spec_helper.rb. le YAML module a deux méthodes principales que vous utiliserez: déverser, qui sort les données sérialisées sous forme de chaîne. ensuite, charge prend la chaîne de données et la recouvre en objets Ruby.

Nous avons donc créé ce fichier avec des données. Avant :chaque test, nous allons créer un Bibliothèque objet, en lui transmettant le nom du fichier YAML. Voyons maintenant les tests:

décrivent "#new" le contexte "sans paramètres" "le fait" n'a pas de livres "lib = Bibliothèque.new le.bloc devrait avoir (0) le contexte .books end end" avec un paramètre de fichier yaml "le faire" a cinq livres "do @ lib.should have (5) .books end end end it it" renvoie tous les livres d'une catégorie donnée "do @ lib.get_books_in_category (: development) .length.should == 2 end it" accepte les nouveaux livres "do @ lib.add_book (Book.new ("Conception pour le Web", "Mark Boulton",: design)) @ lib.get_book ("Conception pour le Web"). devrait être_an_instance_of Fin du livre "enregistre la bibliothèque" do books = @ lib.books.map | book | book.title @ lib.save lib2 = Library.new "books.yml" books2 = lib2.books.map | book | book.title books.should eql books2 end

Nous commençons avec un intérieur décrire bloquer spécialement pour le Bibliothèque # nouveau méthode. Nous introduisons un autre bloc ici: le contexte Cela nous permet de spécifier un contexte pour les tests qu'il contient ou de spécifier différents résultats pour différentes situations. Dans notre exemple, nous avons deux contextes différents: "sans paramètres". et? avec un paramètre de fichier yaml ?; ceux-ci montrent les deux comportements pour utiliser Bibliothèque # nouveau.

Notez également les adaptateurs de test que nous utilisons dans ces deux tests: lib.should have (0) .books et @ lib.should have (5) .books. L'autre façon d'écrire ce serait lib.books.length.should == 5, mais ce n'est pas aussi lisible. Cependant, cela montre que nous avons besoin d’un livres propriété qui est un tableau des livres que nous avons.

Ensuite, nous avons trois autres tests pour tester la fonctionnalité d'obtenir des livres par catégorie, d'ajouter un livre à la bibliothèque et d'enregistrer la bibliothèque. Tout cela échoue, alors écrivons la classe maintenant.

class Library attr_accessor: books def initialize lib_file = false @lib_file = lib_file @books = @lib_file? YAML :: load (File.read (@lib_file)): [] end def get_books_in_category category @ books.select do | livre | book.category == catégorie fin et définition de def add_book book @ books.push fin de livre get_book title @ books.select do | livre | book.title == title end.first end def save lib_file = false @lib_file = lib_file || @lib_file || "library.yml" File.open @lib_file, "w" do | f | f.write YAML :: dump @books fin fin fin

Nous pourrions écrire plus de tests et ajouter beaucoup d'autres fonctionnalités à cette Bibliothèque classe, mais nous nous arrêterons là. Maintenant en cours d'exécution spécification de rspec, vous verrez que tous les tests réussissent.

Cela ne nous donne cependant pas beaucoup d'informations sur les tests. Si vous voulez en voir plus, utilisez le paramètre de format imbriqué: Spécification rspec --format imbriqué. Vous verrez ceci:


Quelques derniers joueurs

Avant de terminer, laissez-moi vous montrer quelques autres joueurs.

  • obj.shose be_true, obj.shose be_false, obj.shose be_nil, obj.shose be_empty - les trois premiers pourraient être réalisés par == vrai, etc. être vide sera vrai si obj.empty? est vrai.
  • obj.should - cet objet existe-t-il même encore?
  • obj.should have_at_most (n) .items, object.should have_at_least (n) .items - comme avoir, mais passera s'il y a plus ou moins de n articles, respectivement.
  • obj.should include (a [, b ,?]) - sont un ou plusieurs éléments dans un tableau?
  • obj.should match (string_or_regex) - l'objet correspond-il à la chaîne ou à l'expression régulière?
  • obj.should raise_exception (error) - cette méthode génère-t-elle une erreur lorsqu'elle est appelée?
  • obj.should respond_to (nom_méthode) - cet objet a-t-il cette méthode? Peut prendre plus d'un nom de méthode, en chaînes ou en symboles.

Vouloir apprendre plus?

Rspec est l’un des meilleurs frameworks de test en Ruby, et vous pouvez en faire beaucoup. Pour en savoir plus, consultez le site Web de Rspec. Il y a aussi le livre The Rspec, qui enseigne plus que Rspec: il s'agit de TDD et de BDD en Ruby. Je le lis maintenant, et il est extrêmement complet et approfondi.

Eh bien, c'est tout pour cette leçon! La prochaine fois, nous verrons comment utiliser Rspec pour tester les interfaces dans une application Web..