RSpec:如何将"let"变量作为参数传递给共享示例

mpi*_*ask 6 rspec ruby-on-rails

规范的相关片段看起来像这样:

let(:one_place) { create(:place) }
let(:other_place) { create(:place) }
let(:data) { "saved data" }

shared_examples "saves data to right place" do |right_place|
  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", one_place
end

context "when whatever it saves to other place" do  
  it_behaves_like "saves data to right place", other_place
end
Run Code Online (Sandbox Code Playgroud)

并且它可以与常量参数完美配合,但在这种情况下我收到一个错误:

one_place在示例组(例如a describecontext块)上不可用.它只能从内individualexamples(例如it块),或从在一个例子(例如范围运行构建体before,let等).

在这种情况下如何将一个懒惰创建的变量传递给共享示例?

Mit*_*tch 5

文档中,我认为您需要将let语句放入传递给的块中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
Run Code Online (Sandbox Code Playgroud)


thi*_*ign 5

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)