Rspec允许变量在块之前不在示例之间变化

时间:2017-07-11 03:28:34

标签: ruby-on-rails ruby rspec

在rspec 3.2中,我有一些基于以下伪代码的东西:

mqtt.subscribe("/wassim/#")

每个示例都会在 let frame = CGRect(x: 160, y: 200, width: 60, height: 40) let yourTextField = UITextField(frame: frame) cell.contentView.addSubview(yourTextField) 设置为context 'my test context' do before do method_that_uses(error_message) end subject { post :my_action, params: a_bunch_of_params } let(:error_message) { 'error' } it { is_expected.to raise_error(MyException) } let(:error_message) { 'different error' } it { is_expected.to redirect_to(a_path) } let(:error_message) { 'third error' } it { is_expected.to redirect_to(another_path) } end 的情况下运行。我也通过从前钩子中运行pry来证实这一点。我怎样才能获得理想的行为?

1 个答案:

答案 0 :(得分:3)

这是因为内部let使用了define_method source for let。您可以创建一个快速示例

class A
  def create_method(name, &block)
    self.class.send(:define_method, name, &block)
  end
end

a = A.new
a.create_method(:foo) { puts "bar" }
a.create_method(:foo) { puts "baz" }
a.foo

并运行它,您会看到define_method使用新方法覆盖上一个方法。因此,在您的示例中,您创建了一个方法,然后在您有机会调用它之​​前两次覆盖它的定义。

您希望在其自己的上下文中运行每个error_message,如下所示:

def method_that_uses(e)
  puts "running with: #{e}"
end

context 'my test context' do
  before do
    method_that_uses(error_message)
  end

  context 'error' do
    let(:error_message) { 'error' }

    it { puts "run one" }
  end

  context 'second error' do
    let(:error_message) { 'different error' }

    it { puts "run two" }
  end

  context' third error' do
    let(:error_message) { 'third error' }

    it { puts "run three" }
  end
end

,运行时输出

running with: error
run one
.running with: different error
run two
.running with: third error
run three
.

这是有效的,因为describecontext数据块会创建新的ExampleGroupsource)和ExampleGroup个州

  

示例组主体(例如describecontext块)在ExampleGroup的新子类的上下文中进行评估。

因此,let(:error_message)现在正在不同的子类上定义这些方法。