在传递给RSpec共享示例的块的情况下,启用`let`分配形式参数

时间:2014-01-03 16:00:52

标签: ruby rspec

在RSpec中,为共享示例提供值的一种技术是使用let来定义该示例使用的变量,如this documentation中所述。

目前,传递给形式参数的值优先于let建立的任何值,如以下示例所示:

shared_examples_for "foo" do |x1|
  specify {puts [x1, x2, x3].inspect}
end

describe "" do
  let(:x1) {3}
  let(:x2) {3}
  let(:x3) {3}
  it_behaves_like "foo", 1 do
    let(:x1) {2}
    let(:x2) {2}
  end
end

# => [1, 2, 3]

我的问题是,改变RSpec语义是否可能/合理/可取,以便传递块内的let设置的变量优先于传递的参数,上面会输出{{ 1}}。这将允许将“简单”值作为参数传递,并通过块设置更复杂的值。

2 个答案:

答案 0 :(得分:5)

  

使用let来定义变量

let没有定义变量;它定义了一个memoized帮助方法。区别很重要,因为ruby以不同的方式处理变量和方法。具体来说,局部变量(例如x1块中的shared_examples_for块arg)始终优先于同名方法,除非您使用self.x1制作它明确表示您正在发送消息。

所以,回答你的问题:不,你问的是不可能的。我认为这也不可取;当有名称冲突时,局部变量总是“赢”对于能够推断你的代码是非常重要的。如果情况并非如此,请考虑重新调查。假设你开始使用这段代码:

# in superclass.rb
class Superclass
end

# in subclass.rb
class Subclass < Superclass
  def do_something(name)
    # do something with the `name` variable
  end
end

在将来的某个时间点,Superclass会更新为name方法:

class Superclass
  def name
    "superclass name"
  end
end

如果ruby没有优先考虑方法的局部变量,那么Subclass#do_something方法会被Superclass的无关更改打破。局部变量始终优先的事实意味着您可以更容易地推断出代码的作用而不必担心在某些远程代码中进行更改会突然导致特定标识符重新绑定到方法而不是局部变量。

答案 1 :(得分:0)

如果我只想用新的context更改上下文,我会使用let s。

您可以在context块内部或外部使用describe块。基本相同,但为您创建一种方式以不同的方式组织您的规范(IMO更好)

describe "adding a credit card" do
  let(:card_number) { "123456789012" }

  it "accepts cards" do
    pending
    # do something with card_number
  end

  context "failure" do
    let(:card_number) { "BLUEBEARD666" }

    it "doesn't handle weird formats" do
      # oh yeah!
    end
  end
end

在这种情况下,您拥有嵌入式let,但它在语义上更有意义。

我希望这不会完全忽略这一点:P