在函数内创建RSpec上下文

时间:2014-10-23 23:04:38

标签: ruby-on-rails ruby rspec

为了避免在我的Rspec测试中重复自己,我想写一个这样的函数

def with_each_partner(&block)
  PARTNER_LIST.each do |partner|
    context "with partner #{partner.name}" { yield partner }
  end
end

我有这样一个功能,它的工作原理是所有测试都以正确的值提供给合作伙伴,但是他们不会在输出期间打印作为"与合作伙伴X&#的一部分34;上下文:相反,如果我有这样的测试:

describe Thing do
  subject { Thing.new(partner) }
  with_each_partner do |partner|
    it 'does its thing' do
      expect(subject.do).to eq 'its thing'
    end
  end
end

我最终输出如下:

Thing
  does its thing

而不是所需的输出,如:

Thing
  with partner X
    does its thing
  with partner Y
    does its thing

如何让RSpec正确使用我的函数中创建的上下文?

1 个答案:

答案 0 :(得分:7)

TL; DR:这样做:

def with_each_partner(&block)
  PARTNER_LIST.each do |partner|
    context "with partner #{partner.name}" do
      class_exec(&block)
    end
  end
end

解释

RSpec的DSL通过评估具有更改self的块来工作 - 这是itdescribe块中的方法的context,但不是在它之外。当您yield时,将使用原始self评估提供的块,该self在定义块的位置为with_each_partner。这意味着使用原始describe Thing do subject { Thing.new(partner) } with_each_partner do |partner| it 'does its thing' do expect(subject.do).to eq 'its thing' end end end 定义,此代码:

describe Thing do
  subject { Thing.new(partner) }
  outer_example_group = self
  with_each_partner do |partner|
    outer_example_group.it 'does its thing' do
      expect(subject.do).to eq 'its thing'
    end
  end
end

真的像这样评估:

"with partner #{partner.name}"

...所以单个示例在外部示例组上定义,而不是在class_exec嵌套组上定义。

class_exec evaluates the provided block in the context of the class/module。在这种情况下,该类是RSpec为您的上下文生成的示例组子类。使用it可确保在调用context时,接收方是嵌套的{{1}}示例组,而不是外部示例组,从而创建所需的结果。