Ruby 将参数传递给rspec共享示例

Ruby 将参数传递给rspec共享示例,ruby,rspec,parameter-passing,Ruby,Rspec,Parameter Passing,我有一个返回结果集的过程,我想使用rspec测试结果集的有效性。该过程将根据参数返回不同的结果,但有许多示例对所有这些参数都是通用的,因此我想创建一组通用示例,可以针对所有参数运行 我知道首选的做法是使用let来构建结果。问题是每个过程需要一两分钟才能生成结果,我大概有30个例子。基于不同参数的所有排列,我正在运行大约500个示例。如果我必须为每个示例重建结果,测试将运行一天以上 因此,我在before(:all)块中生成一个结果,并将其指定给如下属性: RSpec.describe 'Test

我有一个返回结果集的过程,我想使用rspec测试结果集的有效性。该过程将根据参数返回不同的结果,但有许多示例对所有这些参数都是通用的,因此我想创建一组通用示例,可以针对所有参数运行

我知道首选的做法是使用let来构建结果。问题是每个过程需要一两分钟才能生成结果,我大概有30个例子。基于不同参数的所有排列,我正在运行大约500个示例。如果我必须为每个示例重建结果,测试将运行一天以上

因此,我在before(:all)块中生成一个结果,并将其指定给如下属性:

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
shared_examples_for "A result" do |argument|
 # some tests with argument
end
it_behaves_like "A result", my_argument
也许有比使用属性更好的方法。我想这样做:

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
shared_examples_for "A result" do |argument|
 # some tests with argument
end
it_behaves_like "A result", my_argument

在此上下文中使用属性失败。有其他方法吗?

您可以使用
let

let(:result)     { build_result({some_parameters}) }
这将创建一个实例变量,您可以在以后的测试中使用它

根据以下文件:

当您必须指定一个变量而不是使用before块 创建一个实例变量,使用let。使用让变量lazy 仅当它在测试中第一次使用并缓存时加载 直到特定测试完成

坏的

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

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

您可以将参数传递给以下共享示例:

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
shared_examples_for "A result" do |argument|
 # some tests with argument
end
it_behaves_like "A result", my_argument
然后像这样传入
my_参数

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
shared_examples_for "A result" do |argument|
 # some tests with argument
end
it_behaves_like "A result", my_argument

您可以将所有关于结果的断言组合到一个示例中。这样,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

这确实违反了“一次测试,一次断言”的指导方针,但如果操作成本非常高,我认为这是一种合理的方法。使用时,每个断言都会有单独的失败,因此您不会错过这一点。

如果要将参数传递给共享的示例规范文件,您应该使用

it_behaves_like 'SHARED_EXAMPLE_NAME', { params1: param2, param2: param2 }
您还可以传递参数而不进行散列封装。这取决于您将如何在共享文件中使用该参数。 在我的例子中,我必须使用动态参数调用API

RSpec.shared_examples 'SHARED_EXAMPLE_NAME' do |params = {}|

仅供参考:您不能将工厂数据作为参数传递到共享规范文件中。您必须显式地将工厂调用到共享的\u示例规范文件中。

您可以使用块传递参数:

功能“索引页”,js:true-do
上下文“筛选器”do
在{访问(统计数字\路径)}之前
它的行为类似于“选择输入的页面”,%i[create]do
鉴于(:date){date.treaty}
结束
结束
结束
带有选择输入的共享示例
页面将接收包含的参数
功能
[:创建]

shared_examples'页面,带有选择输入'do'功能|
上下文“带结果的表”,js:true-do
鉴于(:已存在的号码){‘号码_1’}
鉴于(:创建的号码){'number_2'}
鉴于(:search_regexp){numb}
场景“您可以选择已存在的号码”,跳过:!功能。包括?(:选择)do
编号选择器。选择编号选项(现有编号)
单击“查找”
期望(第页)有_css('.table tr td',文本:已存在_编号)
结束
场景“您可以使用新名称创建标记”,跳过:!功能。包括?(:创建)do
编号选择器。创建标记(创建编号)
单击“查找”
期望(第页)有_css('.table tr td',文本:created_number)
结束
场景“您可以通过正则表达式搜索”,跳过:!功能。包括?(:regexp)do
数字选择器。选择所有出现的(搜索\u regexp)
单击“查找”
期望(第页)有_css('.table tr td',文本:已存在_编号)
期望(第页)有_css('.table tr td',文本:created_number)
结束
结束
结束

使用let的问题在于,它只在示例期间被缓存。如果我在测试中有10个“it”,那么它将计算let变量的值10次。在我的例子中,我必须为整个上下文构建一次结果,而不是为每个“it”。否则,我的单元测试将运行一天以上,没有人会使用它们。您可以使用来防止这种行为,并在示例之间缓存
let
。这不是我所希望的,但这是迄今为止最好的答案。这是您访问此页面时寻找的答案,如果
my_参数
是用
let
?这行不通。和@gamliela的问题一样。使用
let
定义的变量是否可以传递给共享_示例?@gamliela,如果使用
let
定义了
my_参数
,则无需将其作为参数传递。您只需在
共享\u示例中直接使用它即可
@gamliela您可以将factory bot参数作为参数传递,并在示例组中在
中让
使用这些参数。