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.
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!
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!
Buch
KlasseBeginnen 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
!
Bibliothek
KlasseDieser 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:
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.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.