2016-09-21 2 views
5

У меня есть процесс, который возвращает набор результатов, который я хочу проверить на валидность с помощью rspec. Процесс будет возвращать разные результаты на основе параметров, но есть много примеров, которые являются общими для всех из них, поэтому я хотел бы создать набор общих примеров, которые я могу выполнить против всех из них.Передача параметров в общий пример rspec

Я знаю, что предпочтительной практикой является использование, позволяющее построить результат. Проблема в том, что каждый процесс занимает минуту или две, чтобы создать результат, и у меня есть, вероятно, 30 примеров. Со всеми перестановками, основанными на разных параметрах, я запускаю около 500 примеров. Если мне пришлось перестроить результат для каждого примера, тест продлится более суток.

Так вместо этого я строю результат в ранее (: все) блока и назначение его в атрибуте что-то вроде этого:

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 

Может быть, есть лучший способ, чем с помощью атрибута. Я хочу сделать что-то вроде этого:

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 

Использование атрибута в этом контексте не выполняется. Есть ли другой способ сделать это?

ответ

1

Вы могли бы группу все, что вам утверждения о результате в одном примере. Таким образом, let оценивается только один раз.

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 

Он идет против «один тест, один утверждение» основного положения, но если операция очень дорого, я считаю, что это разумный подход. С :aggregate_failures вы получите отдельные сбои для каждого утверждения, поэтому вы не упустите это.

+0

Это не то, на что я надеялся, но это лучший ответ. –

0

вы можете использовать let.

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

Это создает переменную экземпляра, которую вы можете использовать в своем тесте позже.

Аккорд документации по let,

Когда вы должны назначить переменную вместо использования перед тем блоком, чтобы создать переменную экземпляра, используйте пусть. Использование переменной lazy загружается, только когда оно используется в первый раз в тесте и получает кешированный , пока этот конкретный тест не будет завершен.

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 

ХОРОШО

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

Проблема с использованием let заключается в том, что он кэшируется только в течение всего примера.Если у меня есть 10 "это в моем тесте, тогда он будет вычислять значение переменной let 10 раз. В моем случае крайне важно, чтобы я построил результат один раз для всего контекста, а не для каждого «этого». В противном случае мои модульные тесты будут работать более одного дня, и никто их не будет использовать. –

12

Вы можете передать аргументы общих примеров, как это:

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

А потом пройти в my_argument, как это:

it_behaves_like "A result", my_argument 
+2

Это должен быть принятый ответ. – mikias

Смежные вопросы