Wydaje się, że ludzie wyjaśnili niektóre podstawowe sposoby, w jakie się różnią, ale pominęli before(:all)
i nie wyjaśniają dokładnie, dlaczego należy ich używać.
Uważam, że zmienne instancji nie mają miejsca w większości specyfikacji, częściowo z powodów wymienionych w tej odpowiedzi , więc nie wspomnę o nich tutaj jako o opcji.
niech bloki
Kod w let
bloku jest wykonywany tylko wtedy, gdy jest przywoływany, leniwe ładowanie oznacza to, że kolejność tych bloków jest nieistotna. Daje to dużą moc do ograniczenia powtarzających się konfiguracji w Twoich specyfikacjach.
Jednym (bardzo małym i wymyślnym) przykładem tego jest:
let(:person) { build(:person) }
subject(:result) { Library.calculate_awesome(person, has_moustache) }
context 'with a moustache' do
let(:has_moustache) { true }
its(:awesome?) { should be_true }
end
context 'without a moustache' do
let(:has_moustache) { false }
its(:awesome?) { should be_false }
end
Jak widać, has_moustache
w każdym przypadku definiuje się to inaczej, ale nie ma potrzeby powtarzania subject
definicji. Należy zauważyć, że let
zostanie użyty ostatni blok zdefiniowany w bieżącym kontekście. Jest to dobre przy ustawianiu wartości domyślnych, które mają być używane dla większości specyfikacji, które w razie potrzeby można nadpisać.
Na przykład sprawdzenie zwracanej wartości, calculate_awesome
jeśli przekazano person
model z top_hat
ustawionym na true, ale bez wąsów, byłoby:
context 'without a moustache but with a top hat' do
let(:has_moustache) { false }
let(:person) { build(:person, top_hat: true) }
its(:awesome?) { should be_true }
end
Kolejna rzecz, na którą należy zwrócić uwagę w przypadku bloków let, nie należy ich używać, jeśli szukasz czegoś, co zostało zapisane w bazie danych (tj. Library.find_awesome_people(search_criteria)
), Ponieważ nie zostaną one zapisane w bazie danych, chyba że zostały już przywołane. let!
lub before
bloki są tym, co powinno być tutaj używane.
Ponadto, nigdy nie używaj before
do wyzwalania wykonywania let
bloków, do tego let!
jest stworzone!
pozwolić! Bloki
let!
bloki są wykonywane w kolejności, w jakiej zostały zdefiniowane (podobnie jak przed blokiem). Jedyną podstawową różnicą w porównaniu z blokami przed blokami jest to, że otrzymujesz jawne odniesienie do tej zmiennej, zamiast konieczności powrotu do zmiennych instancji.
Podobnie jak w przypadku let
bloków, jeśli let!
zdefiniowano wiele bloków o tej samej nazwie, podczas wykonywania zostanie użyty najnowszy. Podstawowa różnica polega na tym, że let!
bloki będą wykonywane wiele razy, jeśli zostaną użyte w ten sposób, podczas gdy let
blok będzie wykonywany tylko ostatnim razem.
przed (: każdym) blokami
before(:each)
jest ustawieniem domyślnym przed blokiem i dlatego można do niego odwoływać się jako before {}
zamiast określania pełnego za before(:each) {}
każdym razem.
Osobiście wolę używać before
bloków w kilku podstawowych sytuacjach. Użyję przed blokami, jeśli:
- Używam kpiny, karczowania lub gry podwójnej
- Istnieje dowolna konfiguracja o rozsądnych rozmiarach (zazwyczaj jest to znak, że cechy fabryczne nie zostały poprawnie skonfigurowane)
- Istnieje wiele zmiennych, do których nie muszę się odwoływać bezpośrednio, ale są one wymagane do konfiguracji
- Piszę testy kontrolerów funkcjonalnych w railsach i chcę wykonać określone żądanie testowania (tj
before { get :index }
.). Nawet jeśli subject
w wielu przypadkach możesz tego użyć , czasami wydaje się to bardziej wyraźne, jeśli nie potrzebujesz odniesienia.
Jeśli zauważysz, że piszesz duże before
bloki dla swoich specyfikacji, sprawdź swoje fabryki i upewnij się, że w pełni rozumiesz cechy i ich elastyczność.
przed (: wszystkie) bloki
Są one wykonywane tylko raz, przed specyfikacjami w bieżącym kontekście (i jego potomkach). Można je wykorzystać z wielką korzyścią, jeśli zostaną poprawnie napisane, ponieważ w pewnych sytuacjach może to ograniczyć wykonanie i wysiłek.
Jednym z przykładów (który prawie w ogóle nie wpłynąłby na czas wykonania) jest wyśmiewanie zmiennej ENV na potrzeby testu, co należy zrobić tylko raz.
Mam nadzieję, że to pomoże :)