2012-09-28 23 views
19

以下是M Hartl的Ruby on Rails教程中的一段代碼。任何人都可以解釋爲什麼實例變量(@user)是必要的,爲什麼不使用局部變量。另外,由於實例變量應該是類實例中的變量,哪個類是@user實例化的?rspec中的實例變量如何工作?

require 'spec_helper' 

describe User do 

    before { @user = User.new(name: "Example User", email: "[email protected]") } 

    subject { @user } 

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

回答

32

使用該實例中的局部變量將意味着其範圍將被限制在before,從而導致錯誤。 @user是User類型的,但是是describe塊的實例變量。 Rspec有一些神奇的功能,可以在每個describe塊中創建一個類。每個示例(it塊)最終都是該類的一個子類。類繼承讓示例看到@user

編輯的2017年5月14日

鏈接的博客文章不再可用。使用Wayback Machine鏈接進行更新+在此處內聯相關部分。

請注意,這被認爲是一個反模式,詳見blog post。改爲使用let

let具有以下優點:

  • 在一個實例中多次使用時它memoized,而是跨越實施例不 。
  • 它是延遲加載的,所以你不會浪費時間爲未引用它的例子初始化變量。
  • 如果變量名中有拼寫錯誤,會引發異常。
+1

哦,我想我現在明白了。我一直認爲使用describe塊可以使測試對人類更具可讀性,而不是別的。謝謝:) – TradeRaider

+0

該博客文章不再可用。可能值得更新答案,以包括爲什麼使用實例變量是反模式並刪除斷開的鏈接的原因。 – keoghpe

2

subject ad it塊在不同的範圍內,所以局部變量將不起作用。 @user屬於由RSpec生成的類。

12

您不能使用局部變量,因爲局部變量僅存在於本地方法的範圍內。 before,subjectit在同一個類中生成不同的作用域。

下面的代碼

before { user = User.new(name: "Example User", email: "[email protected]") } 

會提高,當你調用它

subject { user } 

實例@user未定義的變量是類的一個實例User(畢竟,你User.new創建)。

但是,您可能希望使用let命令,而不是實例變量。另外,如果您定義了

subject { User.new(name: "Example User", email: "[email protected]") } 

不需要使用before。您還可以獲得額外的好處,以獲得訪問實例的subject方法,等於定義let(:subject)

+4

使用'let'指定+1:let(:user){User.create(name:「Example User」,email:「[email protected]」)}' – Meltemi

+0

+1使用主題:subject {User。新(名稱:「示例用戶」,電子郵件:「[email protected]」)} –