RSpec:如何将“让”变量作为参数传递给共享示例

时间:2022-05-27 00:24:09

The relevant fragment of spec looks like that:

规格的相关片段如下:

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

And it would works perfectly with constant parameters, but in this case I receive an error:

它可以很好地处理常数参数,但是在这个例子中,我收到了一个错误:

one_place is not available on an example group (e.g. a describe or context block). It is only available from within individualexamples (e.g. it blocks) or from constructs that run in the scope of an example (e.g. before, let, etc).

示例组(例如描述或上下文块)上没有one_place。它只能从单个示例(例如,It块)或在示例范围内运行的构造(例如,before、let等)中获得。

How to pass a lazily created variable to shared examples in such a case?

在这种情况下,如何将延迟创建的变量传递给共享示例?

4 个解决方案

#1


2  

From the docs, I think you need to put your let statement in a block passed to it_behaves_like:

从文档中,我认为您需要将您的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

#2


1  

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

#3


1  

  1. You can use let variables as below too:
  2. 您也可以使用以下的let变量:
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.

注:仅在插补时使用双引号。

  1. You can make your spec DRY as below :
  2. 您可以让您的规格干燥如下:
%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

#4


0  

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.

我想指出的是,不幸的是,你想要实现的目标是不可能实现的。这样做是可取的,因为它使这些变量的用法更加明确。上面提到的解决方案(定义让您在哪里使用it_behaves_like)可以工作,但我发现像这样编写的共享示例令人困惑。

I use this to make required variables explicit in shared examples:

我用它使共享示例中的必需变量显式:

RSpec.shared_examples "saves data to right place" do
  it "(shared example requires `right_place` to be set)" do
    temp_config = RSpec::Expectations.configuration.on_potential_false_positives
    RSpec::Expectations.configuration.on_potential_false_positives = :nothing

    expect { right_place }.to_not raise_error(NameError)

    RSpec::Expectations.configuration.on_potential_false_positives = temp_config
  end

  # ...
end

context "..." do
  let(:right_place) { "" }
  it_behaves_like "saves data to right place"
end

#1


2  

From the docs, I think you need to put your let statement in a block passed to it_behaves_like:

从文档中,我认为您需要将您的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

#2


1  

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

#3


1  

  1. You can use let variables as below too:
  2. 您也可以使用以下的let变量:
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.

注:仅在插补时使用双引号。

  1. You can make your spec DRY as below :
  2. 您可以让您的规格干燥如下:
%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

#4


0  

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.

我想指出的是,不幸的是,你想要实现的目标是不可能实现的。这样做是可取的,因为它使这些变量的用法更加明确。上面提到的解决方案(定义让您在哪里使用it_behaves_like)可以工作,但我发现像这样编写的共享示例令人困惑。

I use this to make required variables explicit in shared examples:

我用它使共享示例中的必需变量显式:

RSpec.shared_examples "saves data to right place" do
  it "(shared example requires `right_place` to be set)" do
    temp_config = RSpec::Expectations.configuration.on_potential_false_positives
    RSpec::Expectations.configuration.on_potential_false_positives = :nothing

    expect { right_place }.to_not raise_error(NameError)

    RSpec::Expectations.configuration.on_potential_false_positives = temp_config
  end

  # ...
end

context "..." do
  let(:right_place) { "" }
  it_behaves_like "saves data to right place"
end