Ruby for Newbies Testen mit Rspec

Ruby ist eine der beliebtesten Sprachen im Internet. Wir führen hier eine Session zu Nettuts + durch, die Sie in Ruby einführt, sowie die großartigen Frameworks und Tools, die mit der Ruby-Entwicklung einhergehen. In dieser Episode erfahren Sie, wie Sie Ihren Ruby-Code mit Rspec testen, einer der besten Testbibliotheken der Branche.


Ich bevorzuge einen Screencast?

Ähnlich aussehend?

Wenn Sie mein aktuelles Tutorial zu JasmineJS gelesen haben, werden Sie wahrscheinlich einige Ähnlichkeiten in Rspec feststellen. Eigentlich sind die Ähnlichkeiten in Jasmine: Jasmine wurde mit Blick auf Rspec erstellt. Wir werden uns ansehen, wie man Rspec verwenden kann, um TDD in Ruby auszuführen. In diesem Lernprogramm erstellen wir einige Ruby-Klassen, um uns mit der Rspec-Syntax vertraut zu machen. Der nächste? Ruby for Newbies? Folge wird Rspec zusammen mit einigen anderen Bibliotheken zum Testen von Web-Apps verwenden? Also bleibt gespannt!


Einrichten

Es ist ziemlich einfach, Rspec zu installieren. Öffnen Sie diese Befehlszeile und führen Sie Folgendes aus:

gem installieren rspec

So einfach.

Lassen Sie uns nun ein kleines Projekt einrichten. Wir werden zwei Klassen erstellen: Buch und Bibliothek. Unsere Buch Objekte speichern nur Titel, Autor und Kategorie. Unsere Bibliothek object speichert eine Liste von Büchern, speichert sie in einer Datei und ermöglicht es uns, sie nach Kategorien abzurufen.

So sollte Ihr Projektverzeichnis aussehen:

Wir geben die Spezifikationen (oder Spezifikationen) in ein spez Mappe; Wir haben für jede Klasse eine Spezifikationsdatei. Beachten Sie die spec_helper.rb Datei. Damit unsere Spezifikationen laufen können, müssen wir benötigen die Ruby-Klassen, die wir testen. Das machen wir im Inneren spec_helper Datei:

required_relative '? / Bibliothek 'required_relative'? / book 'erfordern' yaml '

(Hast du getroffen required_relative noch? Nein? Gut, required_relative ist wie benötigen, Anstatt dass Sie Ihren Ruby-Pfad durchsuchen, wird gesucht relativ zum aktuellen Verzeichnis.)

Sie sind möglicherweise nicht mit dem YAML-Modul vertraut. YAML ist eine einfache Textdatenbank, die wir zum Speichern von Daten verwenden. Sie werden sehen, wie es funktioniert, und wir werden später mehr darüber sprechen.

Nun, da wir alles eingerichtet haben, lassen Sie uns an einigen Spezifikationen knacken!


Das Buch Klasse

Beginnen wir mit den Tests für die Buch Klasse.

erfordern 'spec_helper' beschreiben das Buch do end

So fangen wir an: mit a beschreiben Block. Unser Parameter zu beschreiben erklärt, was wir testen: Dies könnte eine Zeichenfolge sein, aber in unserem Fall verwenden wir den Klassennamen.

Also, was werden wir hier hineinbringen beschreiben Block?

vorher: jedes do @book = Book.new "Titel", "Autor",: Kategorieende

Wir beginnen mit einem Anruf bei Vor; Wir übergeben das Symbol :jeder um anzugeben, dass dieser Code vor jedem Test ausgeführt werden soll (wir könnten das auch tun :alles um es einmal vor allen Tests auszuführen). Was genau machen wir vor jedem Test? Wir erstellen eine Instanz von Buch. Beachten Sie, wie wir es zu einer Instanzvariablen machen, indem Sie den Variablennamen voranstellen @. Wir müssen dies tun, damit unsere Variable innerhalb unserer Tests verfügbar ist. Andernfalls erhalten wir nur eine lokale Variable, die nur innerhalb von Vor Block? das ist überhaupt nicht gut.

Weitermachen,

beschreiben "#new" do it "benötigt drei Parameter und gibt ein Book-Objekt zurück" do @ book.should be_an_instance_of Book end end

Hier ist unser erster Test. Wir benutzen ein verschachteltes beschreiben Block hier, um zu sagen, dass wir die Aktionen einer bestimmten Methode beschreiben. Sie werden feststellen, dass ich den String verwendet habe, #new ?; Es ist eine Konvention in Ruby, sich auf Instanzmethoden wie folgt zu beziehen: Klassenname # Methodenname Da haben wir den Klassennamen in unserem Top-Level beschreiben, Wir setzen hier nur den Methodennamen ein.

Unser Test bestätigt einfach, dass wir tatsächlich ein Buchobjekt gemacht haben.

Beachten Sie die Grammatik, die wir hier verwenden: object.should do_something. Neunundneunzig Prozent Ihrer Tests haben die folgende Form: Sie haben ein Objekt und beginnen mit dem Aufruf sollte oder sollte nicht auf dem Objekt. Dann übergeben Sie den Aufruf an eine andere Funktion an dieses Objekt. In diesem Fall ist das so be_an_instance_of (was braucht Buch als einzigen Parameter). Alles in allem ist dies ein perfekt lesbarer Test. Das ist sehr klar @Buch sollte eine Instanz der Klasse sein Buch. Also lass es laufen.

Öffnen Sie Ihr Terminal, CD in das Projektverzeichnis und ausführen rspec spec. Das spez ist der Ordner in dem rspec werde die Tests finden. Sie sollten in der Ausgabe etwas über "nicht initialisiertes konstantes Objekt :: Buch" sagen; das bedeutet nur, dass es keine gibt Buch Klasse. Lass uns das reparieren.

Laut TDD möchten wir nur genügend Code schreiben, um dieses Problem zu beheben. In dem book.rb Datei, das wäre das:

Klasse Buchende

Führen Sie den Test erneut aus (rspec spec), und Sie werden feststellen, dass es gut geht. Wir haben keine initialisieren Methode, so aufrufend Ruby # neu hat momentan keine Wirkung. Aber wir können schaffen Buch Objekte (wenn auch hohle). Normalerweise würden wir diesen Prozess durch den Rest unserer Entwicklung verfolgen: Schreiben Sie einen Test (oder ein paar verwandte Tests), beobachten Sie, wie er fehlschlägt, lassen Sie ihn passieren, refactorieren, wiederholen. Für dieses Tutorial zeige ich Ihnen nur die Tests und den Code, und wir werden sie besprechen.

Also mehr Tests für Buch:

beschreiben "#title" do it "gibt den richtigen Titel zurück" do @ book.title.should eql "Titel" end end beschreiben "#author" do it "gibt den richtigen Autor zurück" do @ book.author.should eql "Author" end end description "#category" do it "gibt die richtige Kategorie zurück" do @ book.category.should eql: category end end

Es sollte Ihnen alles recht klar sein. Beachten Sie jedoch, wie wir im Test vergleichen: mit Gl. Es gibt drei Möglichkeiten, die Gleichheit mit Rspec zu testen: Verwenden des Operators == oder die Methode Gl beide kehren zurück wahr wenn die beiden Objekte den gleichen Inhalt haben. Zum Beispiel sind beide Zeichenfolgen oder Symbole, die dasselbe sagen. Dann gibt es gleich, was nur true zurückgibt, ist in beiden Objekten wirklich und wirklich gleich, was bedeutet, dass es sich um dasselbe Objekt im Speicher handelt. In unserem Fall, Gl (oder ==) wollen wir.

Diese werden fehlschlagen, also hier der Code für Buch um sie durchzulassen:

Klassenbuch attr_accessor: title,: author,: category def initialisiert title, author, category @title = title @author = author @category = category end end

Lass uns weitergehen zu Bibliothek!


Speccing die Bibliothek Klasse

Dieser wird etwas komplizierter sein. Beginnen wir damit:

"spec_helper" muss als "Bibliotheksobjekt" bezeichnet werden. Vorher tun: do do lib_obj = [Book.new ("JavaScript: The Good Parts", "Douglas Crockford",: Entwicklung), Book.new ("Gestalten mit Webstandards", " Jeffrey Zeldman ",: design), Book.new (" Mach mich nicht zum Nachdenken "," Steve Krug ",: Benutzerfreundlichkeit), Book.new (" JavaScript-Patterns "," Stoyan Stefanov ",: Entwicklung), Buch. neu ("Responsive Web Design", "Ethan Marcotte",: Design)] File.open "books.yml", "w" do | f | f.write YAML :: dump lib_obj end end vor: each dolib = Library.new "books.yml" end end

Dies ist alles vorbereitet: Wir verwenden zwei Vor Blöcke: einen für :jeder und einer für :alles. In dem vor allen Block erstellen wir eine Reihe von Büchern. Dann öffnen wir die Datei? Books.yml? (im wite-Modus) und verwenden YAML um das Array in die Datei zu sichern.

Kurze Kaninchen-Spur, um YAML etwas besser zu erklären: YAML ist laut Site ein menschenfreundlicher Serialisierungsstandard für alle Programmiersprachen. Es ist wie eine textbasierte Datenbank, irgendwie wie JSON. Wir importieren YAML in unsere spec_helper.rb. Das YAML Das Modul hat zwei Hauptmethoden, die Sie verwenden können: Dump, welche die serialisierten Daten als String ausgibt. Dann, Belastung Nimmt die Datenzeichenfolge und konvertiert sie zurück in Ruby-Objekte.

Wir haben diese Datei also mit einigen Daten erstellt. Vor :jeder test, wir werden eine erstellen Bibliothek übergibt den Namen der YAML-Datei. Nun sehen wir uns die Tests an:

Beschreibe "#new" do context "ohne Parameter" do it "hat keine Bücher" do lib = Library.new lib.should (0) .books end end context "mit einem yaml-Dateiparameter" do it "hat fünf Bücher "do @ lib.should have (5) .books end end end it" gibt alle Bücher in einer bestimmten Kategorie zurück "do @ lib.get_books_in_category (: development) .length.should == 2 ende es" akzeptiert neue Bücher "do @ lib.add_book (Book.new ("Gestalten für das Web", "Mark Boulton",: design)) @ lib.get_book ("Gestalten für das Web") = @ lib.books.map | book | book.title @ lib.save lib2 = Library.new "books.yml" books2 = lib2.books.map | book | book.title books.hould sollte eql books2 enden

Wir beginnen mit einem inneren beschreiben Block speziell für die Bibliothek # neu Methode. Wir führen hier einen weiteren Block ein: Kontext Auf diese Weise können wir einen Kontext für Tests angeben oder unterschiedliche Ergebnisse für verschiedene Situationen festlegen. In unserem Beispiel haben wir zwei verschiedene Kontexte: "ohne Parameter". und? mit einem yaml-Dateiparameter ?; Diese zeigen die beiden Verhaltensweisen für die Verwendung Bibliothek # neu.

Beachten Sie auch die Test-Matcher, die wir in diesen beiden Tests verwenden: lib.sollte (0) .books haben und @ lib.sollte (5) .books haben. Die andere Möglichkeit, dies zu schreiben, wäre lib.books.length.should == 5, aber das ist nicht so lesbar. Es zeigt sich jedoch, dass wir eine haben müssen Bücher Eigenschaft, die ein Array der Bücher ist, die wir haben.

Dann haben wir drei weitere Tests, um die Funktionalität zu testen, Bücher nach Kategorie zu erhalten, ein Buch zur Bibliothek hinzuzufügen und die Bibliothek zu speichern. Diese scheitern alle, also schreiben wir die Klasse jetzt.

Klassenbibliothek 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 | book | book.category == Kategorie end end def add_book book @ books.push book end def get_book title @ books.select do | book | 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 end end end

Wir könnten weitere Tests aufschreiben und viele weitere Funktionen hinzufügen Bibliothek Klasse, aber wir werden dort aufhören. Jetzt läuft rspec spec, Sie werden sehen, dass alle Tests bestanden sind.

Dies gibt uns jedoch nicht so viele Informationen über die Tests. Wenn Sie mehr anzeigen möchten, verwenden Sie den geschachtelten Formatparameter: rspec spec --format verschachtelt. Sie werden das sehen:


Ein paar letzte Matchers

Bevor wir fertig sind, lass mich dir ein paar andere Matchers zeigen

  • obj.sollte_wahr sein, obj.should be_false, obj.should be_nil, obj.sollte leer sein - Die ersten drei davon könnten von erledigt werden == wahr, usw. be_empty wird wahr sein, wenn obj.empty? ist wahr.
  • obj.sollte existieren - Gibt es dieses Objekt überhaupt noch??
  • obj.should have_at_most (n) .items, object.should have_at_least (n) .items - mögen haben, wird aber passieren, wenn es mehr oder weniger als gibt n Artikel.
  • obj.should enthalten (a [, b ,?]) - sind ein oder mehrere Elemente in einem Array?
  • obj.should passen (string_or_regex) - Stimmt das Objekt mit der Zeichenfolge oder dem regulären Ausdruck überein??
  • obj.should raise_exception (Fehler) - bewirkt diese Methode beim Aufruf einen Fehler?
  • obj.should reply_to (method_name) - Hat dieses Objekt diese Methode? Kann mehr als einen Methodennamen annehmen, entweder in Zeichenfolgen oder Symbolen.

Möchten Sie mehr erfahren??

Rspec ist eines der besten Frameworks für das Testen in Ruby, und es gibt eine Menge, die Sie damit machen können. Weitere Informationen finden Sie auf der Rspec-Website. Es gibt auch das The Rspec-Buch, das mehr als nur Rspec lehrt: In Ruby dreht sich alles um TDD und BDD. Ich lese es jetzt und es ist äußerst gründlich und tiefgehend.

Nun, das ist alles für diese Lektion! Nächstes Mal werden wir uns ansehen, wie wir Rspec verwenden können, um die Schnittstellen in einer Web-App zu testen.