RSpec: Jaka jest różnica między blokiem let i A before?

Jaka jest różnica między let A before blokiem w RSpec?

I kiedy używać każdego z nich?

Jakie będzie dobre podejście (let lub before) w poniższym przykładzie?

let(:user) { User.make !}
let(:account) {user.account.make!}

before(:each) do
 @user = User.make!
 @account = @user.account.make!
end

Studiowałem ten post stackoverflow

Ale czy dobrze jest zdefiniować let dla rzeczy asocjacyjnych jak powyżej?

Author: Community, 2011-05-12

4 answers

Wydaje się, że ludzie wyjaśnili niektóre z podstawowych sposobów, w jakie się różnią, ale pominęli before(:all) i nie wyjaśniają dokładnie, dlaczego powinny być używane.

Uważam, że zmienne instancji nie mają miejsca na użycie w zdecydowanej większości specyfikacji, częściowo ze względu na powody wymienione w ta odpowiedź , więc nie wspomnę o nich jako opcji tutaj.

Let blocks

Kod w bloku let jest wykonywany tylko wtedy, gdy odwołuje się, leniwe Ładowanie tego oznacza to, że kolejność tych bloków jest nieistotna. Daje to dużą ilość energii, aby ograniczyć powtarzające się konfiguracje za pomocą specyfikacji.

Jeden (bardzo mały i wymyślny) przykład tego to:

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

Widać, że has_moustache w każdym przypadku definiuje się inaczej, ale nie ma potrzeby powtarzania definicji subject. Należy zauważyć, że zostanie użyty ostatni let blok zdefiniowany w bieżącym kontekście. Jest to dobre dla ustawienia domyślnego, który ma być używany dla większość specyfikacji, które można zastąpić w razie potrzeby.

Na przykład, sprawdzanie wartości zwracanej calculate_awesome jeśli przekazany model person z top_hat ustawiony na true, ale nie będzie:

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 temat bloków let, nie powinny być używane, jeśli szukasz czegoś, co zostało zapisane w bazie danych (tj. Library.find_awesome_people(search_criteria)), ponieważ nie zostaną zapisane w bazie danych, chyba że zostały już odwołane. let! lub before bloki są tym, co powinno być używane proszę.

Również, nigdy nigdy użyj before, aby uruchomić wykonywanie let bloków, do czego jest stworzony let!!

Let! bloki

let! bloki są wykonywane w kolejności, w jakiej zostały zdefiniowane(podobnie jak przed blokiem). Podstawowa różnica w stosunku do bloków przed polega na tym, że otrzymujesz wyraźne odniesienie do tej zmiennej, zamiast konieczności powrotu do zmiennych instancji.

Jak w przypadku let bloków, jeśli wiele let! bloków jest zdefiniowana tą samą nazwą, najnowsza jest tym, co zostanie użyte w wykonaniu. 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 będą wykonywane tylko ostatni raz.

Before (: each) blocks

before(:each) jest domyślnym blokiem przed blokiem i dlatego może być odwoływany jako before {} zamiast każdorazowo określać pełne before(:each) {}.

To moje osobiste preferencje, aby używać before bloków w kilku rdzeniach sytuacje. Użyję przed blokami, jeśli:

  • I ' m using mocking, stubbing or doubles
  • Jest to znak, że Twoje cechy fabryczne nie zostały poprawnie skonfigurowane.]}
  • istnieje wiele zmiennych, których nie muszę bezpośrednio odwoływać, ale są wymagane do konfiguracji
  • piszę testy kontrolerów funkcjonalnych w rails i chcę wykonać konkretne żądanie testowania (np. before { get :index }). Mimo, że możesz użyć subject dla to w wielu przypadkach czasami wydaje się bardziej wyraźne, jeśli nie potrzebujesz odniesienia.

Jeśli znajdziesz się pisząc Duże before bloki dla specyfikacji, Sprawdź swoje fabryki i upewnij się, że w pełni rozumiesz cechy i ich elastyczność.

Before (: all) blocks

Są one wykonywane tylko raz, przed specyfikacją w bieżącym kontekście (i jego dziećmi). Można je wykorzystać na wielką korzyść, jeśli są napisane poprawnie, ponieważ istnieją pewne sytuacje może to ograniczyć wykonanie i wysiłek.

Jednym z przykładów (który w ogóle nie wpłynie na czas wykonania) jest wyszydzanie zmiennej ENV do testu, co powinieneś zrobić tylko raz.

Mam nadzieję, że to pomoże:)

 129
Author: Jay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-11 00:52:26

Prawie zawsze, wolę let. Post, który linkujesz określa, że let jest również szybszy. Jednak czasami, gdy trzeba wykonać wiele poleceń, mogę użyć before(:each), ponieważ jego składnia jest bardziej przejrzysta, gdy zaangażowanych jest wiele poleceń.

W twoim przykładzie zdecydowanie wolałbym użyć let zamiast before(:each). Ogólnie rzecz biorąc, kiedy tylko jakaś inicjalizacja zmiennej jest wykonywana, lubię używać let.

 25
Author: Spyros,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-12 20:42:23

Duża różnica, o której nie wspomniano, polega na tym, że zmienne zdefiniowane przez let nie są tworzone, dopóki nie wywołasz ich po raz pierwszy. Tak więc, podczas gdy before(:each) blok tworzy instancje wszystkich zmiennych, let zdefiniujmy liczbę zmiennych, których można użyć w wielu testach, nie tworzy on ich automatycznie. Nie wiedząc o tym, twoje testy mogą wrócić do gry, jeśli oczekujesz, że wszystkie dane zostaną wcześniej załadowane. W niektórych przypadkach możesz nawet chcieć zdefiniuj liczbę zmiennych let, a następnie użyj bloku before(:each), aby wywołać każdą instancję let, aby upewnić się, że dane są dostępne na początku.

 15
Author: mikeweber,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-09 16:35:53

Wygląda na to, że używasz Mechanika. Uważaj, możesz zobaczyć pewne problemy z make! wewnątrz let (wersja non-bang) dzieje się poza globalną transakcją fixture (jeśli używasz również opraw transakcyjnych), więc psując dane do innych testów.

 3
Author: Tim Connor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-02 21:53:33