20

这是 M Hartl 的 Ruby on Rails 教程中的一些代码。谁能解释为什么需要实例变量(@user)以及为什么不使用局部变量。另外,由于实例变量应该是类实例中的变量,@user 是从哪个类实例化的?

require 'spec_helper'

describe User do

  before { @user = User.new(name: "Example User", email: "user@example.com") }

  subject { @user }

  it { should respond_to(:name) }
  it { should respond_to(:email) }
end
4

3 回答 3

32

在该实例中使用局部变量意味着它的范围将被限制为before并因此导致错误。是 User 类型,@user但它是describe块的实例变量。Rspec 有一些魔力,可以在运行时从每个describe块中生成一个类。每个示例(it块)最终成为所述类的子类。类继承让示例看到@user

2017-05-14 编辑

链接的博客文章不再可用。在此处使用 Wayback Machine 链接 + 内联相关部分进行更新。

请注意,这被视为反模式,如本博文中所述。改为使用let

let具有以下优点:

  • 它在一个示例中多次使用时会被记住,但不会跨示例使用。
  • 它是延迟加载的,因此您不会浪费时间为不引用它的示例初始化变量。
  • 如果您的变量名中有拼写错误,将引发异常。
于 2012-09-28T18:18:47.453 回答
12

您不能使用局部变量,因为局部变量仅存在于局部方法的范围内。beforesubjectit在同一类中生成不同的范围。

以下代码

before { user = User.new(name: "Example User", email: "user@example.com") }

当你调用它时会引发一个未定义的变量

subject { user }

该实例@user是该类的一个实例User(毕竟,您是使用 来创建它的User.new)。

但是,您可能希望使用该let命令而不是实例变量。另外,如果你定义

subject { User.new(name: "Example User", email: "user@example.com") }

before不需要使用。您还将获得额外的好处,即获得subject可用于访问实例的方法,等于 define let(:subject)

于 2012-09-28T18:19:38.017 回答
2

subject广告it块处于不同的范围内,因此局部变量不起作用。@user属于 RSpec 在后台生成的类。

于 2012-09-28T18:19:19.943 回答