将参数传递给rspec共享示例

时间:2016-09-21 21:23:51

标签: ruby rspec parameter-passing

我有一个进程返回一个结果集,我希望使用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

在此上下文中使用属性失败。有没有不同的方法来做到这一点?

5 个答案:

答案 0 :(得分:53)

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

my_argument

然后像这样传递it_behaves_like "A result", my_argument

ZoneId z = ZoneId.of( “America/Montreal” );
LocalDate today = LocalDate.now( z );

答案 1 :(得分:0)

您可以使用let

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

这将创建一个您可以在以后的测试中使用的实例变量。

根据let

的文件
  

当您必须分配变量而不是使用before块时   创建一个实例变量,使用let。使用让变量懒惰   仅在测试中第一次使用并加载缓存时才加载   直到特定测试结束。

     

<强> 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 :(得分:0)

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

它确实违背了&#34;一个测试,一个断言&#34;指南,但如果操作成本很高,我认为这是一种合理的方法。使用:aggregate_failures,每个断言都会出现单独的失败,因此您不会错过这个失败。

答案 3 :(得分:0)

如果要将参数传递给shared_example规范文件,则应使用

it_behaves_like 'SHARED_EXAMPLE_NAME', { params1: param2, param2: param2 }

您还可以传递参数而无需散列封装。这取决于您如何在共享文件中利用该参数。 就我而言,我必须使用动态参数来调用API。

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

仅供参考::您不能将 Factory 数据作为参数传递给shared_example规范文件。您必须将工厂显式调用到shared_example规范文件中。

答案 4 :(得分:0)

您可以使用块传递参数:

feature 'Index page', js: true do
  context 'Filter' do
    before { visit(statistics_numbers_path) }

    it_behaves_like 'Page with select input', %i[create] do
      given!(:date) { Date.yesterday }
    end
  end
end

共享示例 Page with select input 将接收包含 features 的参数 [:create]

shared_examples 'Page with select input' do |features|
  context 'Table with results', js: true do
    given!(:existed_number) { 'number_1' }
    given!(:created_number) { 'number_2' }
    given!(:search_regexp) { 'numb' }

    scenario 'You can select existed numbers', skip: !features.include?(:select) do
      number_selector.choose_option(existed_number)

      click_on 'Find'

      expect(page).to have_css('.table tr td', text: existed_number)
    end

    scenario 'You can create tags with new names', skip: !features.include?(:create) do
      number_selector.create_tag(created_number)

      click_on 'Find'

      expect(page).to have_css('.table tr td', text: created_number)
    end

    scenario 'You can search by regular expression', skip: !features.include?(:regexp) do
      number_selector.choose_all_occurrences_of(search_regexp)

      click_on 'Find'

      expect(page).to have_css('.table tr td', text: existed_number)
      expect(page).to have_css('.table tr td', text: created_number)
    end
  end
end