Podsumowanie: Temat RSpec to specjalna zmienna, która odnosi się do testowanego obiektu. Można na nim niejawnie ustawić oczekiwania, co obsługuje przykłady jednowierszowe. W niektórych idiomatycznych przypadkach jest to jasne dla czytelnika, ale poza tym jest trudne do zrozumienia i należy go unikać. let
Zmienne RSpec są po prostu zmiennymi, których instancje są leniwie tworzone (zapamiętywane). Nie są tak trudne do naśladowania jak przedmiot, ale nadal mogą prowadzić do splątanych testów, dlatego należy ich używać z rozwagą.
Temat
Jak to działa
Podmiot jest badanym obiektem. RSpec ma wyraźne pojęcie na ten temat. Może być zdefiniowany lub nie. Jeśli tak, RSpec może wywołać na nim metody bez odwoływania się do niego jawnie.
Domyślnie, jeśli pierwszym argumentem najbardziej zewnętrznej przykładowej grupy ( describe
lub context
bloku) jest klasa, RSpec tworzy instancję tej klasy i przypisuje ją do podmiotu. Na przykład następujące przebiegi:
class A
end
describe A do
it "is instantiated by RSpec" do
expect(subject).to be_an(A)
end
end
Możesz samodzielnie zdefiniować temat za pomocą subject
:
describe "anonymous subject" do
subject { A.new }
it "has been instantiated" do
expect(subject).to be_an(A)
end
end
Możesz nadać tematowi nazwę, kiedy ją zdefiniujesz:
describe "named subject" do
subject(:a) { A.new }
it "has been instantiated" do
expect(a).to be_an(A)
end
end
Nawet jeśli nazwiesz temat, nadal możesz odwoływać się do niego anonimowo:
describe "named subject" do
subject(:a) { A.new }
it "has been instantiated" do
expect(subject).to be_an(A)
end
end
Możesz zdefiniować więcej niż jeden nazwany temat. Ostatnio zdefiniowany nazwany podmiot to anonimowy subject
.
Jednak temat jest zdefiniowany,
Instancja jest uruchamiana leniwie. Oznacza to, że niejawna instancja opisanej klasy lub wykonanie przekazanego bloku subject
nie następuje, dopóki subject
w przykładzie nie zostanie odwołany do nazwanego podmiotu. Jeśli chcesz, aby Twój jawny temat był szybko tworzony (zanim uruchomi się przykład w jego grupie), powiedz subject!
zamiast subject
.
Oczekiwania można ustawić na nim niejawnie (bez pisania subject
lub nazwy nazwanego podmiotu):
describe A do
it { is_expected.to be_an(A) }
end
Podmiot istnieje, aby obsługiwać tę jednowierszową składnię.
Kiedy go używać
Niejawny subject
(wywnioskowany z przykładowej grupy) jest trudny do zrozumienia, ponieważ
- Jest uruchamiany za kulisami.
- Czy jest używany niejawnie (przez wywołanie
is_expected
bez jawnego odbiornika), czy jawnie (jakosubject
), nie daje czytelnikowi żadnych informacji o roli lub naturze obiektu, na którym wywoływane jest oczekiwanie.
- Przykładowa składnia jednowierszowa nie ma przykładowego opisu (argument będący ciągiem
it
w normalnej składni przykładu), więc jedyną informacją, jaką posiada czytelnik o celu przykładu, są same oczekiwania.
Dlatego użycie niejawnego tematu jest pomocne tylko wtedy, gdy kontekst jest prawdopodobnie dobrze zrozumiany przez wszystkich czytelników i naprawdę nie ma potrzeby przykładowego opisu . Przykładem kanonicznym jest testowanie walidacji ActiveRecord za pomocą dopasowań shoulda:
describe Article do
it { is_expected.to validate_presence_of(:title) }
end
Wyraźnie anonimowy subject
(zdefiniowany subject
bez nazwy) jest trochę lepszy, ponieważ czytelnik może zobaczyć, jak jest utworzony, ale
- nadal może umieścić instancję podmiotu daleko od miejsca, w którym jest używany (np. na początku przykładowej grupy z wieloma przykładami, które go używają), co nadal jest trudne do naśladowania, i
- ma inne problemy, które ma ukryty podmiot.
Nazwany podmiot podaje nazwę ujawniającą intencje, ale jedynym powodem używania nazwanego podmiotu zamiast let
zmiennej jest to, że chcesz czasami używać anonimowego podmiotu, a właśnie wyjaśniliśmy, dlaczego anonimowy podmiot jest trudny do zrozumienia.
Tak więc legalne wykorzystanie wyraźnie anonimowego subject
lub wymienionego podmiotu jest bardzo rzadkie .
let
zmienne
Jak oni pracują
let
zmienne są podobne do nazwanych przedmiotów, z wyjątkiem dwóch różnic:
- są zdefiniowane za pomocą
let
/ let!
zamiast subject
/subject!
- nie stawiają na anonimowość
subject
ani nie pozwalają na to, by w sposób dorozumiany wywoływać oczekiwania.
Kiedy ich używać
Jest to całkowicie uzasadnione, let
aby ograniczyć powielanie się przykładów. Jednak rób to tylko wtedy, gdy nie zmniejsza to przejrzystości testu. Najbezpieczniejszym momentem do użycia let
jest sytuacja, gdy przeznaczenie let
zmiennej jest całkowicie jasne z jej nazwy (aby czytelnik nie musiał szukać definicji, która może być oddalona o wiele linii, aby zrozumieć każdy przykład) i jest używany w ten sam sposób w każdym przykładzie. Jeśli któraś z tych rzeczy nie jest prawdą, rozważ zdefiniowanie obiektu w zwykłej starej zmiennej lokalnej lub wywołanie metody fabrycznej bezpośrednio w przykładzie.
let!
jest ryzykowne, ponieważ nie jest leniwe. Jeśli ktoś doda przykład do przykładowej grupy, która zawiera zmienną, let!
ale przykład nie potrzebuje let!
zmiennej,
- ten przykład będzie trudny do zrozumienia, ponieważ czytelnik zobaczy
let!
zmienną i zacznie się zastanawiać, czy i jak wpływa ona na przykład
- przykład będzie wolniejszy niż powinien, ze względu na czas potrzebny do utworzenia
let!
zmiennej
Dlatego używaj let!
, jeśli w ogóle, tylko w małych, prostych grupach przykładów, w których jest mniej prawdopodobne, że przyszli autorzy przykładów wpadną w tę pułapkę.
Fetysz polegający na pojedynczym oczekiwaniu na przykład
Istnieje częste nadużywanie tematów lub let
zmiennych, które warto omówić osobno. Niektórzy ludzie lubią ich używać w ten sposób:
describe 'Calculator' do
describe '#calculate' do
subject { Calculator.calculate }
it { is_expected.to be >= 0 }
it { is_expected.to be <= 9 }
end
end
(To jest prosty przykład metody, która zwraca liczbę, dla której potrzebujemy dwóch oczekiwań, ale ten styl może mieć znacznie więcej przykładów / oczekiwań, jeśli metoda zwraca bardziej skomplikowaną wartość, która wymaga wielu oczekiwań i / lub ma wiele skutków ubocznych, które wszyscy potrzebują oczekiwań.)
Ludzie robią to, ponieważ słyszeli, że należy mieć tylko jedno oczekiwanie na przykład (co jest pomieszane z obowiązującą zasadą, że należy testować tylko jedno wywołanie metody na przykład) lub dlatego, że są zakochani w sztuczkach RSpec. Nie rób tego, czy to z anonimowym, nazwanym tematem czy let
zmienną! Ten styl ma kilka problemów:
- Podmiot anonimowy nie jest przedmiotem przykładów - metoda jest przedmiotem. Pisanie testu w ten sposób psuje język, utrudniając myślenie.
- Jak zawsze w przypadku jednowierszowych przykładów, nie ma miejsca na wyjaśnienie znaczenia oczekiwań.
- Temat musi być skonstruowany dla każdego przykładu, który jest powolny.
Zamiast tego napisz jeden przykład:
describe 'Calculator' do
describe '#calculate' do
it "returns a single-digit number" do
result = Calculator.calculate
expect(result).to be >= 0
expect(result).to be <= 9
end
end
end
:aggregate_failures
tagu w linii takiej jakit "marks a task complete", :aggregate_failures do
(wzięta z książki Rails 5 Test Prescriptions)expect(result).to be_between(0, 9)
.expect(result.to_s).to match(/^[0-9]$/)
- wiem, że jest brzydki, ale naprawdę sprawdza to, co mówisz, lub być może użyjbetween
+is_a? Integer
, ale tutaj testujesz ten typ też. I po prostulet
… nie powinno to być przedmiotem troski, a właściwie może być lepiej przewartościować wartości między przykładami. W przeciwnym razie +1 za postlet!
i nie byłem w stanie samodzielnie przekonać moich kolegów z drużyny. Prześlę tę odpowiedź.Subject
ilet
są tylko narzędziami, które pomogą Ci uporządkować i przyspieszyć testy. Używają ich ludzie ze społeczności rspec, więc nie martwię się, czy mogę ich używać, czy nie. Mogą być używane podobnie, ale służą nieco innym celomSubject
umożliwia zadeklarowanie podmiotu testowego, a następnie ponowne użycie go w dowolnej liczbie następujących przypadków testowych. Zmniejsza to powtarzanie się kodu (wysychanie kodu)Let
jest alternatywą dlabefore: each
bloków, które przypisują dane testowe do zmiennych instancji.Let
daje kilka korzyści. Po pierwsze, buforuje wartość bez przypisywania jej do zmiennej instancji. Po drugie, jest oceniany leniwie, co oznacza, że nie jest oceniany, dopóki specyfikacja tego nie zażąda. W ten sposóblet
pomaga przyspieszyć testy. Myślę też, żelet
jest łatwiejszy do odczytaniaźródło
subject
jest tym, co jest testowane, zwykle instancją lub klasą.let
służy do przypisywania zmiennych w testach, które są oceniane leniwie w porównaniu ze zmiennymi instancji. W tym wątku jest kilka fajnych przykładów.https://github.com/reachlocal/rspec-style-guide/issues/6
źródło