0

我有一个 Rails 控制器,我不小心在“create”方法中定义了“edit”方法。

我的控制器出现错误:

class UsersController < ApplicationController
...
  def create
    @user = User.new(params[:user])
    ...

    def edit
      @user = User.find(params[:id])
      @title = "Edit user"
      @check = "BORK" # something I added for testing the rendered output
    end
  end
end

一个示例测试;

it "should have the right title" do
  get :edit, :id => @user
  response.should have_selector('title', :content => 'Edit user')
end

因此,当我运行测试(我使用 rspec)并输出 response.body 时,User edit.html.erb 模板会正确呈现;所有实例变量都是可见的。所以所有的测试都通过了。

正确访问“编辑”URL 会显示错误;模板使用@user 实例变量,并且设置不正确。当然,纠正控制器会修复错误。

我不明白为什么测试完全通过以及为什么在测试中所有实例变量值都是可见的?

我的直觉表明这是一个范围问题?@user 是一个实例变量,并且在测试中它被设置在测试范围内,但在我的控制器中它在内部“编辑”方法的范围内?但是测试是如何找到“编辑”方法的呢?该内部“编辑”方法存在于什么范围内?

4

1 回答 1

3

您应该意识到该构造与语句def一样多是可执行代码。if把它放在另一个方法里面不是无效的,但是直到调用外部方法它才会运行:

>> class Foo
>>   def foo
>>     def bar
>>     end
>>   end
>> end
=> nil 
>> Foo.instance_methods(false)
=> ["foo"] 
>> Foo.new.foo
=> nil 
>> Foo.instance_methods(false)
=> ["foo", "bar"] 

这在您的浏览器中出错的原因是 Rails 每次请求都会重新加载所有(大部分)类。因此,即使您访问了该create操作(这将导致edit方法被定义),以下请求也会再次卸载它。

但是在测试环境中,如果之前的测试调用了该create操作,那么它将edit为未来的测试定义该操作。如果您的测试以不同的顺序运行,您会看到不同的结果(这本身就使依赖它成为一个坏主意)。

一般来说,这当然不是您想要的,所以只需清除它并继续前进:)

于 2011-01-10T10:19:06.813 回答