RSpec - Szybki przewodnik

RSpec to platforma testów jednostkowych dla języka programowania Ruby. RSpec różni się od tradycyjnych frameworków xUnit, takich jak JUnit, ponieważ RSpec jest narzędziem programistycznym opartym na zachowaniu. Oznacza to, że testy napisane w RSpec koncentrują się na „zachowaniu” testowanej aplikacji. RSpec nie kładzie nacisku na to, jak aplikacja działa, ale na to, jak się zachowuje, innymi słowy, co aplikacja faktycznie robi.

Środowisko RSpec

Przede wszystkim musisz zainstalować Rubiego na swoim komputerze. Jeśli jednak nie zrobiłeś tego wcześniej, możesz pobrać i zainstalować Rubiego z głównej witryny Rubiego - Ruby .

Jeśli instalujesz Ruby w systemie Windows, powinieneś mieć tutaj instalator Ruby dla Windows - http://www.rubyinstaller.org

W tym samouczku będziesz potrzebować tylko edytora tekstu, takiego jak Notatnik i konsola wiersza poleceń. W poniższych przykładach będzie używany program cmd.exe w systemie Windows.

Aby uruchomić cmd.exe, po prostu kliknij menu Start i wpisz „cmd.exe”, a następnie naciśnij klawisz Return.

W wierszu poleceń w oknie cmd.exe wpisz następujące polecenie, aby zobaczyć, jakiej wersji Ruby używasz -

ruby -v

Powinieneś zobaczyć poniższe wyjście, które wygląda podobnie do tego -

ruby 2.2.3p173 (2015-08-18 revision 51636) [x64-mingw32]

W przykładach w tym samouczku będzie używany Ruby 2.2.3, ale wystarczy dowolna wersja Rubiego wyższa niż 2.0.0. Następnie musimy zainstalować klejnot RSpec dla twojej instalacji Ruby. Klejnot to biblioteka Ruby, której możesz użyć we własnym kodzie. Aby zainstalować klejnot, musisz użyć rozszerzeniagem Komenda.

Zainstalujmy teraz klejnot Rspec. Wróć do okna cmd.exe i wpisz:

gem install rspec

Powinieneś mieć listę zależnych klejnotów, które zostały zainstalowane, są to klejnoty, które klejnot rspec musi działać poprawnie. Na końcu wyjścia powinieneś zobaczyć coś, co wygląda tak -

Done installing documentation for diff-lcs, rspec-support, rspec-mocks,
   rspec-expectations, rspec-core, rspec after 22 seconds 
6 gems installed

Nie martw się, jeśli wynik nie wygląda dokładnie tak samo. Ponadto, jeśli używasz komputera Mac lub Linux, może być konieczne uruchomieniegem install rspec polecenie za pomocą sudo lub użyj narzędzia takiego jak HomeBrew lub RVM, aby zainstalować gem rspec.

Hello World

Aby rozpocząć, stwórzmy katalog (folder) do przechowywania naszych plików RSpec. W oknie cmd.exe wpisz:

cd \

Następnie wpisz -

mkdir rspec_tutorial

I na koniec wpisz -

cd rspec_tutorial

Stąd utworzymy kolejny katalog o nazwie spec, zrób to, wpisując -

mkdir spec

W tym folderze będziemy przechowywać nasze pliki RSpec. Pliki RSpec są nazywane „specyfikacjami”. Jeśli wydaje ci się to mylące, możesz myśleć o pliku specyfikacji jako pliku testowym. RSpec używa terminu „specyfikacja”, który jest skrótem od „specyfikacji”.

Ponieważ RSpec jest narzędziem testowym BDD, celem jest skupienie się na tym, co robi aplikacja i czy jest zgodna ze specyfikacją. W rozwoju opartym na zachowaniu specyfikacja jest często opisywana jako „historia użytkownika”. RSpec ma na celu wyjaśnienie, czy kod docelowy zachowuje się poprawnie, innymi słowy zgodnie ze specyfikacją.

Wróćmy do naszego kodu Hello World. Otwórz edytor tekstu i dodaj następujący kod -

class HelloWorld

   def say_hello 
      "Hello World!"
   end
   
end

describe HelloWorld do 
   context “When testing the HelloWorld class” do 
      
      it "should say 'Hello World' when we call the say_hello method" do 
         hw = HelloWorld.new 
         message = hw.say_hello 
         expect(message).to eq "Hello World!"
      end
      
   end
end

Następnie zapisz to w pliku o nazwie hello_world_spec.rb w folderze specyfikacji, który utworzyłeś powyżej. Teraz z powrotem w oknie cmd.exe uruchom to polecenie -

rspec spec spec\hello_world_spec.rb

Po zakończeniu polecenia powinieneś zobaczyć wynik, który wygląda następująco -

Finished in 0.002 seconds (files took 0.11101 seconds to load) 
1 example, 0 failures

Gratulacje, właśnie utworzyłeś i uruchomiłeś swój pierwszy test jednostkowy RSpec!

W następnej sekcji będziemy nadal omawiać składnię plików RSpec.

Przyjrzyjmy się bliżej kodowi naszego HelloWorldprzykład. Przede wszystkim, jeśli nie jest to jasne, testujemy funkcjonalnośćHelloWorldklasa. Jest to oczywiście bardzo prosta klasa, która zawiera tylko jedną metodęsay_hello().

Oto ponownie kod RSpec -

describe HelloWorld do 
   context “When testing the HelloWorld class” do 
      
      it "The say_hello method should return 'Hello World'" do 
         hw = HelloWorld.new 
         message = hw.say_hello 
         expect(message).to eq "Hello World!" 
      end
      
   end 
end

Opis Keyword

Słowo describejest słowem kluczowym RSpec. Służy do definiowania „Przykładowej grupy”. Możesz myśleć o „grupie przykładowej” jako o zbiorze testów. Plikdescribesłowo kluczowe może przyjmować nazwę klasy i / lub argument w postaci łańcucha. Musisz także przekazać argument blokowy dodescribe, będzie to zawierało poszczególne testy lub, jak są one znane w RSpec, „Przykłady”. Blok jest po prostu blokiem Ruby wyznaczonym przez Rubydo/end słowa kluczowe.

Słowo kluczowe kontekstu

Plik context słowo kluczowe jest podobne do describe. Może również akceptować nazwę klasy i / lub argument w postaci łańcucha. Powinieneś użyć bloku zcontexttakże. Idea kontekstu polega na tym, że obejmuje on testy określonego typu.

Na przykład możesz określić grupy przykładów z różnymi kontekstami, takimi jak ten -

context “When passing bad parameters to the foobar() method” 
context “When passing valid parameters to the foobar() method” 
context “When testing corner cases with the foobar() method”

Plik context słowo kluczowe nie jest obowiązkowe, ale pomaga dodać więcej szczegółów na temat przykładów, które zawiera.

Słowo kluczowe it

Słowo itto kolejne słowo kluczowe RSpec, które jest używane do definiowania „Przykładu”. Przykładem jest w zasadzie test lub przypadek testowy. Znowu, jakdescribe i context, it akceptuje zarówno nazwę klasy, jak i argumenty łańcuchowe i powinno być używane z argumentem blokowym, oznaczonym za pomocą do/end. W przypadkuit, zwyczajowo przekazuje się tylko łańcuch i argument blokowy. Argument łańcuchowy często używa słowa „powinien” i ma na celu opisanie, jakie konkretne zachowanie powinno się zdarzyć wewnątrzit block. Innymi słowy, opisuje, że oczekiwany wynik dotyczy przykładu.

Zanotuj it block z naszego przykładu HelloWorld -

it "The say_hello method should return 'Hello World'" do

Ciąg znaków jasno określa, co powinno się stać, gdy wywołujemy polecenie przywitania się na wystąpieniu klasy HelloWorld. Ta część filozofii RSpec, przykład to nie tylko test, to także specyfikacja (specyfikacja). Innymi słowy, przykład zarówno dokumentuje, jak i testuje oczekiwane zachowanie twojego kodu Ruby.

Oczekiwane słowo kluczowe

Plik expectsłowo kluczowe jest używane do zdefiniowania „Oczekiwania” w RSpec. Jest to etap weryfikacji, podczas którego sprawdzamy, czy został spełniony określony oczekiwany warunek.

Z naszego przykładu HelloWorld mamy -

expect(message).to eql "Hello World!"

Pomysł z expectstwierdzenia są takie, że czytają jak normalny angielski. Możesz powiedzieć to głośno jako „Spodziewaj się, że zmienna wiadomość będzie równa łańcuchowi„ Hello World ””. Chodzi o to, że jest opisowy, a także łatwy do odczytania, nawet dla nietechnicznych interesariuszy, takich jak kierownicy projektów.

The to keyword

Plik to słowo kluczowe jest używane jako część expectsprawozdania. Pamiętaj, że możesz również użyć rozszerzenianot_tosłowo kluczowe, aby wyrazić coś przeciwnego, gdy chcesz, aby oczekiwanie było fałszywe. Możesz zobaczyć, że to jest używane z kropką,expect(message).to,ponieważ w rzeczywistości jest to zwykła metoda Rubiego. W rzeczywistości wszystkie słowa kluczowe RSpec są tak naprawdę tylko metodami Rubiego.

The eql keyword

Plik eqlsłowo kluczowe jest specjalnym słowem kluczowym RSpec zwanym Matcher. Używasz dopasowań, aby określić, jaki typ warunku testujesz jako prawdziwy (lub fałszywy).

W naszym HelloWorld expect oświadczenie, jasne jest, że eqloznacza równość ciągów. Zauważ, że istnieją różne typy operatorów równości w Rubim, a co za tym idzie różne odpowiadające im dopasowania w RSpec. W dalszej części omówimy wiele różnych typów dopasowań.

W tym rozdziale utworzymy nową klasę Ruby, zapiszemy ją we własnym pliku i utworzymy oddzielny plik specyfikacji do testowania tej klasy.

Po pierwsze, w naszej nowej klasie nazywa się StringAnalyzer. To prosta klasa, która, jak się domyślacie, analizuje ciągi. Nasza klasa ma tylko jedną metodęhas_vowels?który, jak sugeruje jego nazwa, zwraca prawdę, jeśli łańcuch zawiera samogłoski, a fałsz, jeśli nie. Oto implementacja dlaStringAnalyzer -

class StringAnalyzer 
   def has_vowels?(str) 
      !!(str =~ /[aeio]+/i) 
   end 
end

Jeśli korzystałeś z sekcji HelloWorld, utworzyłeś folder o nazwie C: \ rspec_tutorial \ spec.

Usuń plik hello_world.rb, jeśli go masz, i zapisz powyższy kod StringAnalyzer w pliku o nazwie string_analyzer.rb w folderze C: \ rspec_tutorial \ spec.

Oto źródło naszego pliku specyfikacji do testowania StringAnalyzer -

require 'string_analyzer' 

describe StringAnalyzer do 
   context "With valid input" do 
      
      it "should detect when a string contains vowels" do 
         sa = StringAnalyzer.new 
         test_string = 'uuu' 
         expect(sa.has_vowels? test_string).to be true 
      end 
		
      it "should detect when a string doesn't contain vowels" do 
         sa = StringAnalyzer.new 
         test_string = 'bcdfg' 
         expect(sa.has_vowels? test_string).to be false
      end 
      
   end 
end

Zapisz to w tym samym katalogu specyfikacji, nadając mu nazwę string_analyzer_test.rb.

W oknie cmd.exe przejdź do folderu C: \ rspec_tutorial i uruchom to polecenie: dir spec

Powinieneś zobaczyć następujące -

Katalog C: \ rspec_tutorial \ spec

09/13/2015 08:22 AM  <DIR>    .
09/13/2015 08:22 AM  <DIR>    ..
09/12/2015 11:44 PM                 81 string_analyzer.rb
09/12/2015 11:46 PM              451 string_analyzer_test.rb

Teraz mamy zamiar przeprowadzić nasze testy, uruchom polecenie: rspec spec

Gdy przekazujesz nazwę folderu do rspec, uruchamia wszystkie pliki specyfikacji w folderze. Powinieneś zobaczyć ten wynik -

No examples found.

Finished in 0 seconds (files took 0.068 seconds to load)
0 examples, 0 failures

Powodem tego jest to, że domyślnie rspecuruchamia tylko pliki, których nazwy kończą się na „_spec.rb”. Zmień nazwę string_analyzer_test.rb na string_analyzer_spec.rb. Możesz to łatwo zrobić, uruchamiając to polecenie -

ren spec\string_analyzer_test.rb string_analyzer_spec.rb

A teraz biegnij rspec spec, powinieneś zobaczyć wyjście, które wygląda następująco -

F.
Failures:

   1) StringAnalyzer With valid input should detect when a string contains vowels
      Failure/Error: expect(sa.has_vowels? test_string).to be true 
         expected true
            got false
      # ./spec/string_analyzer_spec.rb:9:in `block (3 levels) in <top (required)>'

Finished in 0.015 seconds (files took 0.12201 seconds to load)
2 examples, 1 failure

Failed examples:
rspec ./spec/string_analyzer_spec.rb:6 # StringAnalyzer With valid 
   input should detect when a string contains vowels
Do you see what just happened? Our spec failed because we have a bug in 
   StringAnalyzer. The bug is simple to fix, open up string_analyzer.rb
   in a text editor and change this line:
!!(str =~ /[aeio]+/i)
to this:
!!(str =~ /[aeiou]+/i)

Teraz zapisz zmiany, które właśnie wprowadziłeś w string_analyizer.rb i ponownie uruchom komendę rspec spec, powinieneś zobaczyć wynik, który wygląda następująco -

..
Finished in 0.002 seconds (files took 0.11401 seconds to load)
2 examples, 0 failures

Gratulacje, przykłady (testy) w Twoim pliku specyfikacji są teraz zaliczane. Naprawiliśmy błąd w wyrażeniu regularnym używającym metody samogłosek, ale nasze testy są dalekie od zakończenia.

Warto byłoby dodać więcej przykładów testujących różne typy ciągów wejściowych metodą ma samogłoski.

Poniższa tabela przedstawia niektóre permutacje, które można dodać w nowych Przykładach (blokuje)

Ciąg wejściowy Opis Oczekiwany wynik z has_vowels?
„aaa”, „eee”, „iii”, „o” Tylko jedna samogłoska i żadne inne litery. prawdziwe
„abcefg” `` Co najmniej jedna samogłoska i kilka spółgłosek '' prawdziwe
„mnklp” Tylko spółgłoski. fałszywy
'' Pusty ciąg (bez liter) fałszywy
„abcde55345 & ??” Samogłoski, spółgłoski, cyfry i znaki interpunkcyjne. prawdziwe
„423432 %%% ^ &” Tylko cyfry i znaki interpunkcyjne. fałszywy
„AEIOU” Tylko samogłoski wielkimi literami. prawdziwe
„AeiOuuuA” Tylko wielkie i małe samogłoski. prawdziwe
„AbCdEfghI” Samogłoski i spółgłoski wielkimi i małymi literami. prawdziwe
„BCDFG” Tylko spółgłoski z wielkich liter. fałszywy
'' Tylko białe znaki. fałszywy

Do Ciebie należy decyzja, które przykłady dodać do pliku specyfikacji. Jest wiele warunków do przetestowania, musisz określić, który podzbiór warunków jest najważniejszy i najlepiej przetestować kod.

Plik rspec polecenie oferuje wiele różnych opcji, aby zobaczyć je wszystkie, wpisz rspec-Wsparcie. Poniższa tabela zawiera listę najpopularniejszych opcji i opisuje ich działanie.

Sr.No. Opcja / flaga i opis
1

-I PATH

Dodaje PATH do ścieżki ładowania (wymagania), która rspec używane podczas wyszukiwania plików źródłowych Rubiego.

2

-r, --require PATH

Dodaje określony plik źródłowy, który ma być wymagany w specyfikacji. akta).

3

--fail-fast

Dzięki tej opcji rspec przestanie działać specyfikacje po niepowodzeniu pierwszego przykładu. Domyślnie rspec uruchamia wszystkie określone pliki specyfikacji, niezależnie od liczby błędów.

4

-f, --format FORMATTER

Ta opcja umożliwia określenie różnych formatów wyjściowych. Więcej informacji na temat formatów wyjściowych można znaleźć w sekcji dotyczącej elementów formatujących.

5

-o, --out FILE

Ta opcja powoduje, że rspec zapisuje wyniki testu do pliku wyjściowego FILE zamiast do standardowego wyjścia.

6

-c, --color

Włącza kolor na wyjściu rspec. Pomyślne wyniki przykładu zostaną wyświetlone zielonym tekstem, awarie zostaną wydrukowane czerwonym tekstem.

7

-b, --backtrace

Wyświetla pełne ślady błędów w danych wyjściowych rspec.

8

-w, --warnings

Wyświetla ostrzeżenia Rubiego w danych wyjściowych rspec.

9

-P, --pattern PATTERN

Załaduj i uruchom pliki specyfikacji, które pasują do wzorca WZÓR. Na przykład, jeśli podasz -p „* .rb”, rspec uruchomi wszystkie pliki Ruby, a nie tylko te, które kończą się na „_spec.rb”.

10

-e, --example STRING

Ta opcja kieruje rspec do uruchamiania wszystkich przykładów, które zawierają tekst STRING w swoich opisach.

11

-t, --tag TAG

Z tą opcją rspec będzie uruchamiał tylko przykłady zawierające znacznik TAG. Zauważ, że TAG jest określony jako symbol Ruby. Więcej informacji można znaleźć w sekcji dotyczącej tagów RSpec.

Jeśli pamiętasz nasz oryginalny przykład Hello World, zawierał on wiersz, który wyglądał następująco:

expect(message).to eq "Hello World!"

Słowo kluczowe eql to RSpec„Dopasowujący”. Tutaj przedstawimy inne typy dopasowań w RSpec.

Równość / Dopasowanie tożsamości

Dopasowania do testowania pod kątem równości obiektów lub wartości.

Matcher Opis Przykład
eq Przechodzi, gdy faktyczne == oczekiwano oczekiwać (rzeczywiste). do oczekiwanego równ
eql Przechodzi, gdy current.eql? (Oczekiwane) oczekiwać (rzeczywiste) .do eql oczekiwano
być Przechodzi, gdy faktyczne. Równe? (Oczekiwane) spodziewać się (rzeczywiste)
równy Przechodzi również, gdy current.equal? ​​(Oczekiwane) oczekiwać (rzeczywiste). równe oczekiwane

Przykład

describe "An example of the equality Matchers" do 

   it "should show how the equality Matchers work" do 
      a = "test string" 
      b = a 
      
      # The following Expectations will all pass 
      expect(a).to eq "test string" 
      expect(a).to eql "test string" 
      expect(a).to be b 
      expect(a).to equal b 
   end
   
end

Gdy powyższy kod zostanie wykonany, wygeneruje następujący wynik. Liczba sekund może się nieznacznie różnić na Twoim komputerze -

.
Finished in 0.036 seconds (files took 0.11901 seconds to load)
1 example, 0 failures

Porównanie dopasowań

Dopasowania do porównywania z wartościami.

Matcher Opis Przykład
> Przechodzi, gdy rzeczywisty> oczekiwany oczekiwać (rzeczywiste). być> oczekiwane
> = Przechodzi, gdy rzeczywista> = oczekiwana oczekiwać (rzeczywiste). być> = oczekiwane
< Przechodzi, gdy faktycznie <oczekiwano oczekiwać (rzeczywiste). być <oczekiwane
<= Przechodzi, gdy faktyczne <= oczekiwane oczekiwać (rzeczywiste). być <= oczekiwane
be_between włącznie Przechodzi, gdy wartość rzeczywista wynosi <= min i> = maks oczekiwać (rzeczywiste). to be_between (min, max) .inclusive
be_between na wyłączność Przechodzi, gdy wartość rzeczywista wynosi <min i> maks oczekiwać (rzeczywiste). to be_between (min, max). wyłączne
mecz Przechodzi, gdy rzeczywisty pasuje do wyrażenia regularnego oczekiwać (rzeczywiste). do dopasowania (/ regex /)

Przykład

describe "An example of the comparison Matchers" do

   it "should show how the comparison Matchers work" do
      a = 1
      b = 2
      c = 3		
      d = 'test string'
      
      # The following Expectations will all pass
      expect(b).to be > a
      expect(a).to be >= a 
      expect(a).to be < b 
      expect(b).to be <= b 
      expect(c).to be_between(1,3).inclusive 
      expect(b).to be_between(1,3).exclusive 
      expect(d).to match /TEST/i 
   end
   
end

Gdy powyższy kod zostanie wykonany, wygeneruje następujący wynik. Liczba sekund może się nieznacznie różnić na Twoim komputerze -

. 
Finished in 0.013 seconds (files took 0.11801 seconds to load) 
1 example, 0 failures

Dopasowywanie klas / typów

Dopasowania do testowania typu lub klasy obiektów.

Matcher Opis Przykład
be_instance_of Przechodzi, gdy rzeczywista jest instancją oczekiwanej klasy. oczekiwać (rzeczywiste) .to be_instance_of (oczekiwane)
be_kind_of Przechodzi, gdy rzeczywiste jest instancją oczekiwanej klasy lub którejkolwiek z jej klas nadrzędnych. oczekiwać (rzeczywiste). to be_kind_of (oczekiwane)
odpowiedzi na Przechodzi, gdy rzeczywisty odpowiada na określoną metodę. oczekiwać (rzeczywiste). to respond_to (oczekiwane)

Przykład

describe "An example of the type/class Matchers" do
 
   it "should show how the type/class Matchers work" do
      x = 1 
      y = 3.14 
      z = 'test string' 
      
      # The following Expectations will all pass
      expect(x).to be_instance_of Fixnum 
      expect(y).to be_kind_of Numeric 
      expect(z).to respond_to(:length) 
   end
   
end

Gdy powyższy kod zostanie wykonany, wygeneruje następujący wynik. Liczba sekund może się nieznacznie różnić na Twoim komputerze -

. 
Finished in 0.002 seconds (files took 0.12201 seconds to load) 
1 example, 0 failures

Dopasowania prawda / fałsz / brak

Dopasowania do testowania, czy wartość jest prawdziwa, fałszywa lub zerowa.

Matcher Opis Przykład
Mów prawdę Przechodzi, gdy current == true oczekiwać (rzeczywiste). być prawdziwe
być fałszywe Przechodzi, gdy current == false oczekiwać (rzeczywiste). być fałszywe
be_truthy Przechodzi, gdy wartość rzeczywista nie jest fałszywa ani zerowa oczekiwać (rzeczywistego). to be_truthy
be_falsey Przechodzi, gdy wartość rzeczywista jest fałszywa lub zerowa oczekiwać (faktyczny). to be_falsey
be_nil Przechodzi, gdy wartość rzeczywista wynosi zero oczekiwać (rzeczywiste). to be_nil

Przykład

describe "An example of the true/false/nil Matchers" do
   it "should show how the true/false/nil Matchers work" do
      x = true 
      y = false 
      z = nil 
      a = "test string" 
      
      # The following Expectations will all pass
      expect(x).to be true 
      expect(y).to be false 
      expect(a).to be_truthy 
      expect(z).to be_falsey 
      expect(z).to be_nil 
   end 
end

Gdy powyższy kod zostanie wykonany, wygeneruje następujący wynik. Liczba sekund może się nieznacznie różnić na Twoim komputerze -

. 
Finished in 0.003 seconds (files took 0.12301 seconds to load) 
1 example, 0 failures

Dopasowywanie błędów

Dopasowania do testowania, gdy blok kodu wywołuje błąd.

Matcher Opis Przykład
podnieść_error (ErrorClass) Przechodzi, gdy blok wywołuje błąd typu ErrorClass. spodziewać się {blok} .to podnieść_error (ErrorClass)
podnieść_error ("komunikat o błędzie") Pomija, gdy blok wywołuje błąd z komunikatem „komunikat o błędzie”. oczekuj {blok} .to podnieść_error („komunikat o błędzie”)
podnieść_error (ErrorClass, „komunikat o błędzie”) Przechodzi, gdy blok wywołuje błąd typu ErrorClass z komunikatem „komunikat o błędzie” spodziewać się {blok} .to podnieść_error (ErrorClass, „komunikat o błędzie”)

Przykład

Zapisz poniższy kod w pliku o nazwie error_matcher_spec.rb i uruchom go za pomocą tego polecenia - rspec error_matcher_spec.rb.

describe "An example of the error Matchers" do 
   it "should show how the error Matchers work" do 
      
      # The following Expectations will all pass 
      expect { 1/0 }.to raise_error(ZeroDivisionError)
      expect { 1/0 }.to raise_error("divided by 0") 
      expect { 1/0 }.to raise_error("divided by 0", ZeroDivisionError) 
   end 
end

Gdy powyższy kod zostanie wykonany, wygeneruje następujący wynik. Liczba sekund może się nieznacznie różnić na Twoim komputerze -

. 
Finished in 0.002 seconds (files took 0.12101 seconds to load) 
1 example, 0 failures

W tym rozdziale omówimy dublowanie RSpec, znane również jako makiety RSpec. Double to przedmiot, który może „zastępować” inny przedmiot. Prawdopodobnie zastanawiasz się, co to dokładnie oznacza i dlaczego go potrzebujesz.

Załóżmy, że tworzysz aplikację dla szkoły i masz klasę reprezentującą klasę uczniów i inną klasę dla uczniów, czyli klasę Classroom i klasę Student. Najpierw musisz napisać kod jednej z zajęć, więc powiedzmy, że zacznij od klasy Classroom -

class ClassRoom 
   def initialize(students) 
      @students = students 
   end 
   
   def list_student_names 
      @students.map(&:name).join(',') 
   end 
end

To jest prosta klasa, ma jedną metodę list_student_names, która zwraca rozdzielany przecinkami ciąg nazw uczniów. Teraz chcemy stworzyć testy dla tej klasy, ale jak to zrobić, jeśli jeszcze nie utworzyliśmy klasy Student? Potrzebujemy testu Double.

Ponadto, jeśli mamy „fikcyjną” klasę, która zachowuje się jak obiekt Student, wówczas nasze testy ClassRoom nie będą zależeć od klasy Student. Nazywamy ten test izolacją.

Jeśli nasze testy ClassRoom nie opierają się na innych klasach, to gdy test się nie powiedzie, możemy od razu wiedzieć, że w naszej klasie ClassRoom jest błąd, a nie w jakiejś innej klasie. Pamiętaj, że w prawdziwym świecie możesz budować klasę, która wymaga interakcji z inną klasą napisaną przez kogoś innego.

W tym miejscu przydatne stają się RSpec Doubles (mocks). Nasza metoda list_student_names wywołuje metodę name dla każdego obiektu Studenta w jego zmiennej składowej @students. Dlatego potrzebujemy Double, który implementuje metodę name.

Oto kod dla ClassRoom wraz z przykładem RSpec (test), ale zauważ, że nie ma zdefiniowanej klasy studenta -

class ClassRoom 
   def initialize(students) 
      @students = students 
   end
   
   def list_student_names 
      @students.map(&:name).join(',') 
   end 
end

describe ClassRoom do 
   it 'the list_student_names method should work correctly' do 
      student1 = double('student') 
      student2 = double('student') 
      
      allow(student1).to receive(:name) { 'John Smith'} 
      allow(student2).to receive(:name) { 'Jill Smith'} 
      
      cr = ClassRoom.new [student1,student2]
      expect(cr.list_student_names).to eq('John Smith,Jill Smith') 
   end 
end

Gdy powyższy kod zostanie wykonany, wygeneruje następujący wynik. Upływający czas może się nieznacznie różnić na Twoim komputerze -

. 
Finished in 0.01 seconds (files took 0.11201 seconds to load) 
1 example, 0 failures

Jak widać, używając pliku test doubleumożliwia przetestowanie kodu nawet wtedy, gdy opiera się on na klasie, która jest niezdefiniowana lub niedostępna. Oznacza to również, że gdy zdarzy się niepowodzenie testu, możesz od razu stwierdzić, że jest to spowodowane problemem w Twojej klasie, a nie zajęciami napisanymi przez kogoś innego.

Jeśli przeczytałeś już sekcję o RSpec Doubles (aka Mocks), to już widziałeś RSpec Stubs. W RSpec kod pośredniczący jest często nazywany kodem metody, jest to specjalny rodzaj metody, która „zastępuje” istniejącą metodę lub metodę, która jeszcze nie istnieje.

Oto kod z sekcji dotyczącej RSpec Doubles -

class ClassRoom 
   def initialize(students) 
      @students = students 
   End
   
   def list_student_names 
      @students.map(&:name).join(',') 
   end 
end 

describe ClassRoom do 
   it 'the list_student_names method should work correctly' do 
      student1 = double('student') 
      student2 = double('student') 
      
      allow(student1).to receive(:name) { 'John Smith'}
      allow(student2).to receive(:name) { 'Jill Smith'} 
      
      cr = ClassRoom.new [student1,student2]
      expect(cr.list_student_names).to eq('John Smith,Jill Smith') 
   end 
end

W naszym przykładzie metoda allow () udostępnia kody pośredniczące metod, których potrzebujemy do przetestowania klasy ClassRoom. W tym przypadku potrzebujemy obiektu, który będzie działał jak instancja klasy Student, ale ta klasa w rzeczywistości (jeszcze) nie istnieje. Wiemy, że klasa Student musi udostępniać metodę name () i używamy metody allow (), aby utworzyć skrót metody dla name ().

Należy zauważyć, że składnia RSpec zmieniła się nieco na przestrzeni lat. W starszych wersjach RSpec powyższe kody pośredniczące metody byłyby zdefiniowane w ten sposób -

student1.stub(:name).and_return('John Smith') 
student2.stub(:name).and_return('Jill Smith')

Weźmy powyższy kod i zamieńmy dwa allow() wiersze ze starą składnią RSpec -

class ClassRoom 
   def initialize(students) 
      @students = students 
   end 
   
   def list_student_names 
      @students.map(&:name).join(',') 
   end 
	
end 

describe ClassRoom do 
   it 'the list_student_names method should work correctly' do 
      student1 = double('student') 
      student2 = double('student')
      
      student1.stub(:name).and_return('John Smith')
      student2.stub(:name).and_return('Jill Smith') 
      
      cr = ClassRoom.new [student1,student2] 
      expect(cr.list_student_names).to eq('John Smith,Jill Smith') 
   end 
end

Zobaczysz to wyjście po wykonaniu powyższego kodu -

.
Deprecation Warnings:

Using `stub` from rspec-mocks' old `:should` syntax without explicitly 
   enabling the syntax is deprec 

ated. Use the new `:expect` syntax or explicitly enable `:should` instead. 
   Called from C:/rspec_tuto 

rial/spec/double_spec.rb:15:in `block (2 levels) in <top (required)>'.
If you need more of the backtrace for any of these deprecations 
   to identify where to make the necessary changes, you can configure 

`config.raise_errors_for_deprecations!`, and it will turn the 
   deprecation warnings into errors, giving you the full backtrace.

1 deprecation warning total

Finished in 0.002 seconds (files took 0.11401 seconds to load)
1 example, 0 failures

Zaleca się użycie nowej składni allow (), gdy chcesz utworzyć kody pośredniczące metod w przykładach RSpec, ale udostępniliśmy tutaj starszy styl, abyś mógł go rozpoznać, jeśli go zobaczysz.

Podczas pisania testów jednostkowych często wygodnie jest uruchomić konfigurację i kod dezaktywacji przed i po testach. Kod instalacji to kod, który konfiguruje lub „ustawia” warunki testu. Kod dezaktywacji wykonuje porządki, upewnia się, że środowisko jest spójne dla kolejnych testów.

Ogólnie rzecz biorąc, testy powinny być od siebie niezależne. Kiedy uruchamiasz cały zestaw testów i jeden z nich kończy się niepowodzeniem, chcesz mieć pewność, że się nie powiódł, ponieważ testowany kod zawiera błąd, a nie dlatego, że poprzedni test pozostawił środowisko w niespójnym stanie.

Najpopularniejsze haki używane w RSpec to haki przed i po hakach. Umożliwiają zdefiniowanie i uruchomienie kodu konfiguracji i dezaktywacji, które omówiliśmy powyżej. Rozważmy ten przykładowy kod -

class SimpleClass 
   attr_accessor :message 
   
   def initialize() 
      puts "\nCreating a new instance of the SimpleClass class" 
      @message = 'howdy' 
   end 
   
   def update_message(new_message) 
      @message = new_message 
   end 
end 

describe SimpleClass do 
   before(:each) do 
      @simple_class = SimpleClass.new 
   end 
   
   it 'should have an initial message' do 
      expect(@simple_class).to_not be_nil
      @simple_class.message = 'Something else. . .' 
   end 
   
   it 'should be able to change its message' do
      @simple_class.update_message('a new message')
      expect(@simple_class.message).to_not be 'howdy' 
   end
end

Po uruchomieniu tego kodu otrzymasz następujące dane wyjściowe -

Creating a new instance of the SimpleClass class 
. 
Creating a new instance of the SimpleClass class 
. 
Finished in 0.003 seconds (files took 0.11401 seconds to load) 
2 examples, 0 failures

Przyjrzyjmy się bliżej temu, co się dzieje. Metoda before (: each) służy do definiowania kodu konfiguracji. Kiedy przekazujesz: each argument, instruujesz metodę before, aby była uruchamiana przed każdym przykładem w Twojej grupie przykładów, tj. Dwa, które blokuje wewnątrz bloku opisującego w powyższym kodzie.

W wierszu: @simple_class = SimpleClass.new tworzymy nową instancję klasy SimpleClass i przypisujemy ją do zmiennej instancji obiektu. Jaki obiekt możesz się zastanawiać? RSpec tworzy specjalną klasę za kulisami w zakresie bloku opisu. Umożliwia to przypisywanie wartości zmiennym instancji tej klasy, do których można uzyskać dostęp w ramach bloków it w przykładach. Ułatwia to również pisanie czystszego kodu w naszych testach. Jeśli każdy test (przykład) potrzebuje instancji SimpleClass, możemy umieścić ten kod w podpięciu przed i nie musimy go dodawać do każdego przykładu.

Zwróć uwagę, że wiersz „Tworzenie nowej instancji klasy SimpleClass” jest zapisywany w konsoli dwukrotnie, co pokazuje, że przed wywołaniem przechwytywania w każdym z it blocks.

Jak już wspomnieliśmy, RSpec ma również podpięcie after, a zarówno podpięcia przed, jak i po mogą przyjąć: all jako argument. Hak after będzie działać za określonym celem. Cel: all oznacza, że ​​hak będzie działał przed / po wszystkich przykładach. Oto prosty przykład ilustrujący, kiedy wywoływany jest każdy punkt zaczepienia.

describe "Before and after hooks" do 
   before(:each) do 
      puts "Runs before each Example" 
   end 
   
   after(:each) do 
      puts "Runs after each Example" 
   end 
   
   before(:all) do 
      puts "Runs before all Examples" 
   end 
   
   after(:all) do 
      puts "Runs after all Examples"
   end 
   
   it 'is the first Example in this spec file' do 
      puts 'Running the first Example' 
   end 
   
   it 'is the second Example in this spec file' do 
      puts 'Running the second Example' 
   end 
end

Po uruchomieniu powyższego kodu zobaczysz to wyjście -

Runs before all Examples 
Runs before each Example 
Running the first Example 
Runs after each Example 
.Runs before each Example 
Running the second Example 
Runs after each Example 
.Runs after all Examples

Tagi RSpec zapewniają łatwy sposób uruchamiania określonych testów w plikach specyfikacji. Domyślnie RSpec uruchomi wszystkie testy w uruchamianych plikach specyfikacji, ale może być konieczne wykonanie tylko ich części. Powiedzmy, że masz kilka testów, które działają bardzo szybko i że właśnie dokonałeś zmiany w kodzie aplikacji i chcesz po prostu przeprowadzić szybkie testy. Ten kod pokaże, jak to zrobić za pomocą tagów RSpec.

describe "How to run specific Examples with Tags" do 
   it 'is a slow test', :slow = > true do 
      sleep 10 
      puts 'This test is slow!' 
   end 
   
   it 'is a fast test', :fast = > true do 
      puts 'This test is fast!' 
   end 
end

Teraz zapisz powyższy kod w nowym pliku o nazwie tag_spec.rb. Z wiersza poleceń uruchom następujące polecenie: rspec --tag slow tag_spec.rb

Zobaczysz to wyjście -

Opcje uruchamiania: include {: slow => true}

This test is slow! 
. 
Finished in 10 seconds (files took 0.11601 seconds to load) 
1 example, 0 failures

Następnie uruchom to polecenie: rspec --tag fast tag_spec.rb

Zobaczysz to wyjście -

Run options: include {:fast = >true} 
This test is fast! 
. 
Finished in 0.001 seconds (files took 0.11201 seconds to load) 
1 example, 0 failures

Jak widać, znaczniki RSpec bardzo ułatwiają wykonanie podzbioru testów!

Jedną z mocnych stron RSpec jest to, że zapewnia wiele sposobów pisania testów, czystych testów. Gdy testy są krótkie i czytelne, łatwiej jest skupić się na oczekiwanym zachowaniu, a nie na szczegółach pisania testów. Przedmioty RSpec to kolejny skrót umożliwiający pisanie prostych, nieskomplikowanych testów.

Rozważ ten kod -

class Person 
   attr_reader :first_name, :last_name 
   
   def initialize(first_name, last_name) 
      @first_name = first_name 
      @last_name = last_name 
   end 
end 

describe Person do 
   it 'create a new person with a first and last name' do
      person = Person.new 'John', 'Smith'
      
      expect(person).to have_attributes(first_name: 'John') 
      expect(person).to have_attributes(last_name: 'Smith') 
   end 
end

W rzeczywistości jest to całkiem jasne, ale moglibyśmy użyć funkcji tematu RSpec, aby zmniejszyć ilość kodu w przykładzie. Robimy to, przenosząc instancję obiektu osoby do wiersza opisu.

class Person 
   attr_reader :first_name, :last_name 
   
   def initialize(first_name, last_name) 
      @first_name = first_name 
      @last_name = last_name 
   end 
	
end 

describe Person.new 'John', 'Smith' do 
   it { is_expected.to have_attributes(first_name: 'John') } 
   it { is_expected.to have_attributes(last_name: 'Smith') }
end

Po uruchomieniu tego kodu zobaczysz to wyjście -

.. 
Finished in 0.003 seconds (files took 0.11201 seconds to load) 
2 examples, 0 failures

Zwróć uwagę, o ile prostsza jest druga próbka kodu. Wzięliśmy ten jedenit block w pierwszym przykładzie i zastąpiłem go dwoma it blocks które wymagają mniej kodu i są równie przejrzyste.

Czasami przykłady RSpec wymagają łatwego sposobu udostępniania kodu wielokrotnego użytku. Najlepszym sposobem na osiągnięcie tego jest pomocników. Helpery to w zasadzie zwykłe metody Rubiego, które udostępniasz w przykładach. Aby zilustrować korzyści płynące z używania pomocników, rozważmy ten kod -

class Dog 
   attr_reader :good_dog, :has_been_walked 
   
   def initialize(good_or_not) 
      @good_dog = good_or_not 
      @has_been_walked = false 
   end 
   
   def walk_dog 
      @has_been_walked = true 
   end 
end 

describe Dog do 
   it 'should be able to create and walk a good dog' do 
      dog = Dog.new(true) 
      dog.walk_dog 
      
      expect(dog.good_dog).to be true
      expect(dog.has_been_walked).to be true 
   end 
   
   it 'should be able to create and walk a bad dog' do 
      dog = Dog.new(false) 
      dog.walk_dog 

      expect(dog.good_dog).to be false
      expect(dog.has_been_walked).to be true 
 
   end 
end

Ten kod jest przejrzysty, ale zawsze dobrze jest ograniczyć liczbę powtórzeń kodu, gdy tylko jest to możliwe. Możemy wziąć powyższy kod i zmniejszyć część tego powtórzenia za pomocą metody pomocniczej o nazwie create_and_walk_dog ().

class Dog
   attr_reader :good_dog, :has_been_walked 
   
   def initialize(good_or_not)
      @good_dog = good_or_not 
      @has_been_walked = false 
   end 
   
   def walk_dog 
      @has_been_walked = true 
   end 
end 

describe Dog do 
   def create_and_walk_dog(good_or_bad)
      dog = Dog.new(good_or_bad)
      dog.walk_dog
      return dog 
   end 
   
   it 'should be able to create and walk a good dog' do
      dog = create_and_walk_dog(true)
      
      expect(dog.good_dog).to be true
      expect(dog.has_been_walked).to be true 
   end 
   
   it 'should be able to create and walk a bad dog' do 
      dog = create_and_walk_dog(false)
      
      expect(dog.good_dog).to be false
      expect(dog.has_been_walked).to be true 
   end 
end

Po uruchomieniu powyższego kodu zobaczysz to wyjście -

.. 
Finished in 0.002 seconds (files took 0.11401 seconds to load) 
2 examples, 0 failures

Jak widać, byliśmy w stanie wprowadzić logikę tworzenia i wyprowadzania obiektu psa do Pomocnika, co pozwala na to, aby nasze przykłady były krótsze i czystsze.

RSpec to elastyczne i potężne narzędzie. Funkcjonalność metadanych w RSpec nie jest wyjątkiem. Metadane ogólnie odnoszą się do „danych o danych”. W RSpec oznacza to dane o Twoimdescribe, context i it blocks.

Spójrzmy na przykład -

RSpec.describe "An Example Group with a metadata variable", :foo => 17 do 
   context 'and a context with another variable', :bar => 12 do 
      
      it 'can access the metadata variable of the outer Example Group' do |example| 
         expect(example.metadata[:foo]).to eq(17) 
      end
      
      it 'can access the metadata variable in the context block' do |example|  
         expect(example.metadata[:bar]).to eq(12) 
      end 
      
   end 
end

Po uruchomieniu powyższego kodu zobaczysz to wyjście -

.. 
Finished in 0.002 seconds (files took 0.11301 seconds to load) 
2 examples, 0 failures

Metadane zapewniają sposób przypisywania zmiennych w różnych zakresach w plikach RSpec. Zmienna example.metadata to skrót Ruby, który zawiera inne informacje o grupach Przykłady i Przykłady.

Na przykład przepiszmy powyższy kod, aby wyglądał następująco -

RSpec.describe "An Example Group with a metadata variable", :foo => 17 do
   context 'and a context with another variable', :bar => 12 do 
      
      it 'can access the metadata variable in the context block' do |example|
         expect(example.metadata[:foo]).to eq(17) 
         expect(example.metadata[:bar]).to eq(12) 
         example.metadata.each do |k,v|
         puts "#{k}: #{v}"
      end
		
   end 
end

Kiedy uruchamiamy ten kod, widzimy wszystkie wartości w przykładzie. Hash metadata -

.execution_result: #<RSpec::Core::Example::ExecutionResult:0x00000002befd50>
block: #<Proc:0x00000002bf81a8@C:/rspec_tutorial/spec/metadata_spec.rb:7>
description_args: ["can access the metadata variable in the context block"]
description: can access the metadata variable in the context block
full_description: An Example Group with a metadata variable and a context 
   with another variable can access the metadata variable in the context block
described_class:
file_path: ./metadata_spec.rb
line_number: 7
location: ./metadata_spec.rb:7
absolute_file_path: C:/rspec_tutorial/spec/metadata_spec.rb
rerun_file_path: ./metadata_spec.rb
scoped_id: 1:1:2
foo: 17
bar: 12
example_group:
{:execution_result=>#<RSpec::Core::Example::ExecutionResult:
   0x00000002bfa0e8>, :block=>#<
   Proc:0x00000002bfac00@C:/rspec_tutorial/spec/metadata_spec.rb:2>, 
   :description_args=>["and a context with another variable"], 
	
   :description=>"and a context with another variable", 
   :full_description=>"An Example Group with a metadata variable
   and a context with another variable", :described_class=>nil, 
      :file_path=>"./metadata_spec.rb", 
		
   :line_number=>2, :location=>"./metadata_spec.rb:2", 
      :absolute_file_path=>"C:/rspec_tutorial/spec/metadata_spec.rb",
      :rerun_file_path=>"./metadata_spec.rb", 
		
   :scoped_id=>"1:1", :foo=>17, :parent_example_group=>
      {:execution_result=>#<
      RSpec::Core::Example::ExecutionResult:0x00000002c1f690>, 
      :block=>#<Proc:0x00000002baff70@C:/rspec_tutorial/spec/metadata_spec.rb:1>
      , :description_args=>["An Example Group with a metadata variable"], 
		
   :description=>"An Example Group with a metadata variable", 
   :full_description=>"An Example Group with a metadata variable", 
	:described_class=>nil, :file_path=>"./metadata_spec.rb", 
   :line_number=>1, :location=>"./metadata_spec.rb:1",
   :absolute_file_path=>
	
   "C:/rspec_tutorial/spec/metadata_spec.rb", 
   :rerun_file_path=>"./metadata_spec.rb", 
   :scoped_id=>"1", :foo=>17}, 
   :bar=>12}shared_group_inclusion_backtrace: [] 
	
last_run_status: unknown .
.
Finished in 0.004 seconds (files took 0.11101 seconds to load) 
2 examples, 0 failures

Najprawdopodobniej nie będziesz musiał używać wszystkich tych metadanych, ale spójrz na pełną wartość opisu -

Przykładowa grupa ze zmienną metadanych i kontekstem z inną zmienną może uzyskać dostęp do zmiennej metadanych w bloku kontekstu.

To jest zdanie utworzone z opisu bloku opisu + zawartego w nim opisu bloku kontekstowego + opisu bloku it block.

Warto tutaj zauważyć, że te trzy ciągi czytają się razem jak normalne angielskie zdanie. . . co jest jednym z pomysłów stojących za RSpec, mając testy, które brzmią jak angielskie opisy zachowań.

Możesz przeczytać sekcję o metadanych RSpec przed przeczytaniem tej sekcji, ponieważ, jak się okazuje, filtrowanie RSpec jest oparte na metadanych RSpec.

Wyobraź sobie, że masz plik specyfikacji, który zawiera dwa rodzaje testów (Przykłady): pozytywne testy funkcjonalne i negatywne (błędy) testy. Zdefiniujmy je w ten sposób -

RSpec.describe "An Example Group with positive and negative Examples" do 
   context 'when testing Ruby\'s build-in math library' do
      
      it 'can do normal numeric operations' do 
         expect(1 + 1).to eq(2) 
      end 
      
      it 'generates an error when expected' do
         expect{1/0}.to raise_error(ZeroDivisionError) 
      end
      
   end 
end

Teraz zapisz powyższy tekst jako plik o nazwie „filter_spec.rb”, a następnie uruchom go za pomocą tego polecenia -

rspec filter_spec.rb

Zobaczysz dane wyjściowe, które wyglądają mniej więcej tak -

.. 
Finished in 0.003 seconds (files took 0.11201 seconds to load) 
2 examples, 0 failures

A co by było, gdybyśmy chcieli ponownie uruchomić tylko pozytywne testy w tym pliku? A może tylko negatywne testy? Możemy to łatwo zrobić za pomocą filtrów RSpec. Zmień powyższy kod na ten -

RSpec.describe "An Example Group with positive and negative Examples" do 
   context 'when testing Ruby\'s build-in math library' do
      
      it 'can do normal numeric operations', positive: true do 
         expect(1 + 1).to eq(2) 
      end 
      
      it 'generates an error when expected', negative: true do 
         expect{1/0}.to raise_error(ZeroDivisionError) 
      end
      
   end 
end

Zapisz zmiany w filter_spec.rb i uruchom to nieco inne polecenie -

rspec --tag positive filter_spec.rb

Teraz zobaczysz wyjście, które wygląda następująco -

Run options: include {:positive=>true} 
. 
Finished in 0.001 seconds (files took 0.11401 seconds to load) 
1 example, 0 failures

Określając --tag positive, mówimy RSpec, aby uruchamiał Przykłady tylko ze zdefiniowaną zmienną metadanych: positive. Moglibyśmy zrobić to samo z negatywnymi testami, uruchamiając polecenie w ten sposób -

rspec --tag negative filter_spec.rb

Pamiętaj, że to tylko przykłady, możesz określić filtr o dowolnej nazwie.

RSpec Formatters

Elementy formatujące umożliwiają RSpec wyświetlanie wyników testów na różne sposoby. Utwórzmy nowy plik RSpec zawierający ten kod -

RSpec.describe "A spec file to demonstrate how RSpec Formatters work" do 
   context 'when running some tests' do 
      
      it 'the test usually calls the expect() method at least once' do 
         expect(1 + 1).to eq(2) 
      end
      
   end 
end

Teraz zapisz to w pliku o nazwie formatter_spec.rb i uruchom to polecenie RSpec -

rspec formatter_spec.rb

Powinieneś zobaczyć wyjście, które wygląda następująco -

. 
Finished in 0.002 seconds (files took 0.11401 seconds to load) 
1 example, 0 failures

Teraz uruchom to samo polecenie, ale tym razem określ formater, na przykład:

rspec --format progress formatter_spec.rb

Tym razem powinieneś zobaczyć to samo wyjście -

. 
Finished in 0.002 seconds (files took 0.11401 seconds to load) 
1 example, 0 failures

Powodem jest to, że program formatujący „postęp” jest domyślnym programem formatującym. Spróbujmy teraz innego programu formatującego, spróbuj uruchomić to polecenie -

rspec --format doc formatter_spec.rb

Teraz powinieneś zobaczyć to wyjście -

A spec file to demonstrate how RSpec Formatters work 
   when running some tests 
      the test usually calls the expect() method at least once
Finished in 0.002 seconds (files took 0.11401 seconds to load) 
1 example, 0 failures

Jak widać, wyjście wygląda zupełnie inaczej w przypadku programu formatującego „doc”. Ten formater prezentuje wynik w stylu podobnym do dokumentacji. Możesz się zastanawiać, jak wyglądają te opcje w przypadku niepowodzenia testu (przykład). Zmieńmy kod wformatter_spec.rb wyglądać tak -

RSpec.describe "A spec file to demonstrate how RSpec Formatters work" do 
   context 'when running some tests' do 
      
      it 'the test usually calls the expect() method at least once' do 
         expect(1 + 1).to eq(1) 
      end
      
   end 
end

Oczekiwania expect(1 + 1).to eq(1)powinien zawieść. Zapisz zmiany i ponownie uruchom powyższe polecenia -

rspec --format progress formatter_spec.rb i pamiętaj, ponieważ program formatujący „postęp” jest domyślny, możesz po prostu uruchomić: rspec formatter_spec.rb. Powinieneś zobaczyć to wyjście -

F 
Failures:
1) A spec file to demonstrate how RSpec Formatters work when running some tests 
the test usually calls the expect() method at least once
   Failure/Error: expect(1 + 1).to eq(1)
	
      expected: 1
         got: 2
			  
      (compared using ==)			  
   # ./formatter_spec.rb:4:in `block (3 levels) in <top (required)>'

Finished in 0.016 seconds (files took 0.11201 seconds to load)
1 example, 1 failure
Failed examples:

rspec ./formatter_spec.rb:3 # A spec file to demonstrate how RSpec 
   Formatters work when running some tests the test usually calls 
   the expect() method at least once

Teraz wypróbujmy program formatujący dokumenty, uruchom to polecenie -

rspec --format doc formatter_spec.rb

Teraz, po nieudanym teście, powinieneś zobaczyć ten wynik -

A spec file to demonstrate how RSpec Formatters work
   when running some tests
      the test usually calls the expect() method at least once (FAILED - 1)
		
Failures:

1) A spec file to demonstrate how RSpec Formatters work when running some
   tests the test usually calls the expect() method at least once
   Failure/Error: expect(1 + 1).to eq(1)
	
   expected: 1
        got: 2
		  
   (compared using ==)
   # ./formatter_spec.rb:4:in `block (3 levels) in <top (required)>'
	
Finished in 0.015 seconds (files took 0.11401 seconds to load) 
1 example, 1 failure

Nieudane przykłady

rspec ./formatter_spec.rb:3 # Plik specyfikacji, aby zademonstrować, jak działają elementy formatujące RSpec podczas uruchamiania niektórych testów. Test zwykle wywołuje metodę Expect () przynajmniej raz.

Formattery RSpec oferują możliwość zmiany sposobu wyświetlania wyników testów, możliwe jest nawet utworzenie własnego niestandardowego programu formatującego, ale jest to bardziej zaawansowany temat.

Kiedy uczysz się RSpec, możesz dużo czytać o oczekiwaniach i na początku może to być trochę zagmatwane. Są dwa główne szczegóły, o których należy pamiętać, kiedy zobaczysz termin Oczekiwanie -

  • Oczekiwanie to po prostu stwierdzenie w pliku it block który używa expect()metoda. Otóż ​​to. To nie jest bardziej skomplikowane. Gdy masz taki kod:expect(1 + 1).to eq(2), masz w swoim przykładzie Oczekiwanie. Spodziewasz się, że wyrażenie1 + 1 ocenia do 2. Sformułowanie jest ważne, ponieważ RSpec jest platformą testową BDD. Nazywając tę ​​instrukcję oczekiwaniem, staje się jasne, że kod RSpec opisuje „zachowanie” testowanego kodu. Chodzi o to, że wyrażasz, jak powinien zachowywać się kod, w sposób przypominający dokumentację.

  • Składnia oczekiwań jest stosunkowo nowa. Zanimexpect() Metoda została wprowadzona (w 2012 r.), RSpec używał innej składni, która była oparta na should()metoda. Powyższe oczekiwanie jest zapisane w starej składni w następujący sposób:(1 + 1).should eq(2).

Możesz napotkać starą składnię RSpec dla oczekiwań podczas pracy ze starszym kodem lub starszą wersją RSpec. Jeśli używasz starej składni z nową wersją RSpec, zobaczysz ostrzeżenie.

Na przykład z tym kodem -

RSpec.describe "An RSpec file that uses the old syntax" do
   it 'you should see a warning when you run this Example' do 
      (1 + 1).should eq(2) 
   end 
end

Po uruchomieniu otrzymasz wynik, który wygląda następująco -

. Deprecation Warnings:

Using `should` from rspec-expectations' old `:should` 
   syntax without explicitly enabling the syntax is deprecated. 
   Use the new `:expect` syntax or explicitly enable 
	
`:should` with `config.expect_with( :rspec) { |c| c.syntax = :should }`
   instead. Called from C:/rspec_tutorial/spec/old_expectation.rb:3 :in 
   `block (2 levels) in <top (required)>'.

If you need more of the backtrace for any of these deprecations to
   identify where to make the necessary changes, you can configure 
`config.raise_errors_for_deprecations!`, and it will turn the deprecation 
   warnings into errors, giving you the full backtrace.

1 deprecation warning total 
Finished in 0.001 seconds (files took 0.11201 seconds to load) 
1 example, 0 failures

O ile nie musisz używać starej składni, zdecydowanie zaleca się użycie Expect () zamiast should ().