2011-02-12 58 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