RSpec: How to pass a "let" variable as a parameter to shared examples
From the docs, I think you need to put your let
statement in a block passed to it_behaves_like
:
let(:data) { "saved data" }
shared_examples "saves data to right place" do
it { expect(right_place.data).to eq data }
end
context "when something it saves to one place" do
it_behaves_like "saves data to right place" do
let(:right_place) { create(:place) }
end
end
context "when whatever it saves to other place" do
it_behaves_like "saves data to right place" do
let(:right_place) { create(:place) }
end
end
How to pass a lazily created variable to shared examples in such a case?
What's wrong with good old memoization?
def one_place
@one_place ||= create(:place)
end
I'd point out that what you're trying to accomplish is unfortunately not possible. It would be desirable because it makes the usage of such variables explicit. The mentioned workaround (define let where you use it_behaves_like
) works but I find shared examples written like that to be confusing.
I use a shared example to make required variables explicit in shared examples:
RSpec.shared_examples "requires variables" do |variable_names|
it "(shared example requires `#{variable_names}` to be set)" do
variable_names = variable_names.kind_of?(Array) ? variable_names : [variable_names]
temp_config = RSpec::Expectations.configuration.on_potential_false_positives
RSpec::Expectations.configuration.on_potential_false_positives = :nothing
variable_names.each do |variable_name|
expect { send(variable_name) }.not_to(
raise_error(NameError), "The following variables must be set to use this shared example: #{variable_names}"
)
end
RSpec::Expectations.configuration.on_potential_false_positives = temp_config
end
end
Use it like this:
RSpec.shared_examples "saves data to right place" do
include_examples "requires variables", :right_place
# ...
end
context "..." do
it_behaves_like "saves data to right place" do
let(:right_place) { "" }
end
end
- You can use let variables as below too:
shared_examples 'saves data to right place' do
it { expect(right_place.data).to eq data }
end
context 'when something it saves to one place' do
let(:right_place) { create(:place) }
it_behaves_like 'saves data to right place'
end
context 'when whatever it saves to other place' do
let(:right_place) { create(:place) }
it_behaves_like 'saves data to right place'
end
Note: Use Double quotes only in case of interpolation.
- You can make your spec DRY as below :
%w(one other).each do |location|
let(:right_place) { location == one ? create(:place) : create(:place, :other) }
context "when it saves to #{location} place" do
it_behaves_like 'saves data to right place'
end
end