2011-02-12 65 views
4

我正在閱讀「Ruby on Rails 3教程」一書,並且遇到了必須爲我的靜態頁面編寫一些基本單元測試的部分。我注意到只是一些文字修改複製的代碼,所以我將其更改爲如下所示:Ruby新手變量作用域問題新手

require 'spec_helper' 

describe PagesController do 
    render_views 

    pages = ['home', 'contact', 'about', 'help'] 

    before(:each) do 
    @base_title = "Ruby on Rails Tutorial Sample App | " 
    end 

    pages.each do |page| 
    describe "GET '#{page}'" do 
     it "should be successful" do 
     get "#{page}" 
     response.should be_success 
     end 

     it "should have the right title" do 
     get "#{page}" 
     response.should have_selector("title", :content => @base_title + page.capitalize) 
     end 
    end 
    end 

end 

我感到困惑的在上面的例子是,我可以用這個代替「頁」變量:

@pages = ['home', 'contact', 'about', 'help'] 

它仍然有效。這是爲什麼? '@頁面'和'頁面'有什麼不同?

另一個令人困惑的是,這兩個導致測試失敗:

pages = ['home', 'contact', 'about', 'help'] 
@base_title = "Ruby on Rails Tutorial Sample App | " 

而且

before(:each) do 
    pages = ['home', 'contact', 'about', 'help'] 
    @base_title = "Ruby on Rails Tutorial Sample App | " 
end 

爲什麼上面的兩個例子失敗?爲什麼代碼看起來像我在第一個代碼片段中發佈的內容?我認爲這與變量範圍有關,但我對Ruby仍然陌生,因此我正在尋求更深入的理解。 FWIW,我是一位經驗豐富的C#開發人員,因此獲得可比的Java或C#代碼將幫助我理解這一點或寫得很好的描述。

感謝您的支持。

編輯: 添加了錯誤消息,當我將@base_title移到'before'塊之外時。

Failure/Error: response.should have_selector("title", :content => @base_title + page.capitalize) 
NoMethodError: 
    You have a nil object when you didn't expect it! 
    You might have expected an instance of Array. 
    The error occurred while evaluating nil.+ 
# ./spec/controllers/pages_controller_spec.rb:21:in `block (4 levels) in <top (required)>' 
+0

對於第一個片段,它的方法是什麼?請張貼該背景。另外,如果你在第三個代碼片段中使用`@ pages`(即一個實例變量,而不是局部變量`pages`),它是否工作? – Zabba 2011-02-12 03:48:46

+0

我加了剩下的方法。 – Brandon 2011-02-12 03:53:06

回答

4

K,我要回答你的問題,爲了...

當您從

pages = ['home', 'contact', 'about', 'help'] 

的變化......

@pages = ['home', 'contact', 'about', 'help'] 

你只是把一個局部變量改變成一個實例變量......這不應該起作用,並且應該導致你的測試中斷...

2.下面的代碼不應該工作。

pages = ['home', 'contact', 'about', 'help'] 
@base_title = "Ruby on Rails Tutorial Sample App | " 

這是因爲@base_title不能用於您的「it」「do」塊。變量頁面將在範圍內......但是你有@base_title錯誤條件。

3。這也行不通。

before(:each) do 
    pages = ['home', 'contact', 'about', 'help'] 
    @base_title = "Ruby on Rails Tutorial Sample App | " 
end 

這裏定義的變量頁面超出了每個循環的範圍。 @base_title會很好,並會完美地運用你所有的方法。

- 結論 -

您發佈的最終樣本是正確的。您只需要爲每個循環需要一個局部變量,並且需要一個實例變量(@base_title),以便在測試運行時可用於整個實例化類。希望這對你有所幫助。我建議看看其他一些紅寶石教程在線,我個人喜歡派人到http://rubykoans.com/ =)

最後一個注意事項,RSpec是一個複雜的範圍,因爲它使用了很多塊並且將代碼移動了很多去做它需要的。基本上你有塊內的塊...事情可以很快變得棘手。我會從一些簡單的例子開始。

2

在Ruby中創建一個訪問方法,以允許外部代碼訪問實例變量:

class Foo 
    def pages 
    @pages 
    end 

    def pages=(value) 
    @pages = value 
    end 
end 

如果你從類中訪問@pages,這將是同樣的事情,訪問pages從班內,這將調用self.pages,返回@pages