2016-09-21 29 views
5

Mam proces, który zwraca zestaw wyników, który chcę przetestować pod kątem ważności przy użyciu rspec. Proces zwróci różne wyniki w oparciu o parametry, ale istnieje wiele przykładów, które są wspólne dla wszystkich z nich, dlatego chciałbym stworzyć zestaw typowych przykładów, które można wykorzystać na wszystkich.Przekazywanie parametrów do wspólnego przykładu rspec

Wiem, że preferowaną praktyką jest użycie let do zbudowania wyniku. Problem polega na tym, że każdy proces zajmuje minutę lub dwie, aby wygenerować wynik i mam prawdopodobnie 30 przykładów. Przy wszystkich permutacjach opartych na różnych parametrach używam około 500 przykładów. Jeśli musiałbym przebudować wynik dla każdego przykładu, test trwałby więcej niż jeden dzień.

Zamiast więc buduję skutkować przed (: all) bloku i przypisanie go do czegoś atrybut tak:

RSpec.describe 'Test Description' do 
    attr_reader :result 

    before(:all) 
    @result = build_result({some_parameters}) 
    end 

    context 'Some context' do 
    it 'Looks lik a result' do 
     expect(result.something).to ... 
    end 

    it 'Feels lik a result' do 
     expect(result.something).to ... 
    end 
    end 
end 

Może istnieje lepszy sposób niż za pomocą atrybutu. Chcę zrobić coś takiego:

RSpec.describe 'Test Description' do 
    attr_reader :result 

    before(:all) 
    @result = build_result({some_parameters}) 
    end 

    context 'Some context' do 
    it_behaves_like "A result" result 
    end 
end 

Użycie atrybutu w tym kontekście kończy się niepowodzeniem. Czy jest inny sposób na zrobienie tego?

Odpowiedz

1

Mogłabyś grupa was wszystkich twierdzeń na wynik w jednym przykładzie. W ten sposób let jest oceniany tylko raz.

RSpec.describe 'Test Description' do 
    context 'for params x and y' do 
    let(:expected_x) { 'x' } 
    let(:expected_y) { 'y' } 

    subject { build_result({x: 'x', y: 'y'}) } 

    specify :aggregate_failures do 
     expect(subject.x).to eq(expected_x) 
     expect(subject.y).to eq(expected_y) 
    end 
    end 
end 

To wykracza przeciwko „jeden test i jedna wytyczna” twierdzenie, ale jeśli operacja jest bardzo kosztowna, myślę, że jest to rozsądne podejście. Z :aggregate_failures otrzymasz oddzielne niepowodzenia dla każdego potwierdzenia, więc nie będziesz tego przegapiał.

+0

Nie tego oczekiwałem, ale jest to jak dotąd najlepsza odpowiedź. –

0

można użyć let.

let(:result)  { build_result({some_parameters}) } 

Spowoduje to utworzenie zmiennej instancji, której później można użyć w teście.

Accord dokumentacji na let,

Kiedy trzeba przypisać zmienną zamiast stosowania przed blokiem do utworzyć zmiennej instancji, należy pozwolić. Za pomocą niech zmienna leniwy ładuje się tylko wtedy, gdy jest używana po raz pierwszy w teście i zostaje zbuforowana , dopóki ten konkretny test nie zostanie zakończony.

BAD

describe '#type_id' do 
    before { @resource = FactoryGirl.create :device } 
    before { @type  = Type.find @resource.type_id } 

    it 'sets the type_id field' do 
    expect(@resource.type_id).to equal(@type.id) 
    end 
end 

DOBRY

describe '#type_id' do 
    let(:resource) { FactoryGirl.create :device } 
    let(:type)  { Type.find resource.type_id } 

    it 'sets the type_id field' do 
    expect(resource.type_id).to equal(type.id) 
    end 
end 
+2

Problem z używaniem let jest taki, że jest buforowany tylko w czasie trwania przykładu.Jeśli mam 10 "to" w moim teście, to obliczy wartość zmiennej let 10 razy. W moim przypadku konieczne jest, aby raz zbudować wynik dla całego kontekstu, a nie dla każdego "to". W przeciwnym razie moje testy jednostkowe będą trwały dłużej niż jeden dzień i nikt ich nie użyje. –

12

można przekazywać argumenty do wspólnych przykładów takiego:

shared_examples_for "A result" do |argument| 
# some tests with argument 
end 

, a następnie przekazać w my_argument tak:

it_behaves_like "A result", my_argument 
+2

To powinna być zaakceptowana odpowiedź. – mikias