使用rspec测试设计视图

时间:2013-01-20 16:47:24

标签: ruby-on-rails authentication rspec devise tdd

我已经生成了运行rails g devise:views的Devise的视图,现在想测试它们。

这就是我的想法:

require 'spec_helper'

describe "devise/sessions/new" do
    before do
        render
    end

    it "renders the form to log in" do
        rendered.should have_selector("form", action: user_session_path, method: :post) do |form|

        end
    end
end

对于render语句,它给了我undefined local variable or method 'resource'。在googling around之后我发现我应该添加

@user.should_receive(:resource).and_return(User.new)

在render语句之前 - 但它仍然给我同样的错误,我不确定如何使用它。

我做错了什么?谢谢你的帮助。

7 个答案:

答案 0 :(得分:13)

只是另一个想法,任何人遇到同样的问题。我不是很喜欢向我的助手添加代码只是为了让测试可以通过,所以我最终在我的测试中在前一块中添加了这段代码:

before do
  view.stub(:resource).and_return(User.new)
  view.stub(:resource_name).and_return(:user)
  view.stub(:devise_mapping).and_return(Devise.mappings[:user])
end

答案 1 :(得分:5)

whaddya知道吗?我找到了this answer,其中有人有类似的问题。解决方案是在应用程序帮助程序中包含以下代码:

def resource_name
  :user
end

def resource
  @resource ||= User.new
end

def devise_mapping
  @devise_mapping ||= Devise.mappings[:user]
end

这是必要的,因为设计在其控制器中使用某些辅助方法。但是,如果我从我的规范访问视图,这些辅助方法不可用,因此我的测试失败。将这些方法放在应用程序帮助器中可以在整个应用程序中访问它们,包括我的规范,实际上测试通过了!

答案 2 :(得分:4)

像Mike Fogg一样,我不喜欢向ApplicationController添加几个方法,只是为了让这些视图规范正常工作。

我注意到我的rspec安装有一个spec/mixins目录,所以我做了以下内容:

# spec/mixins/devise_helpers.rb
module DeviseHelpers
  def resource_name
    :user
  end

  def resource
    @resource ||= User.new
  end

  def devise_mapping
    @devise_mapping ||= Devise.mappings[:user]
  end
end

然后加入我的规范:

# spec/views/devise/registrations/new.html.haml_spec.rb
require 'rails_helper'
include DeviseHelpers

describe 'devise/registrations/new.html.haml' do
  it 'has a login link for existing users' do
    render
    expect(rendered).to have_link('Log in')
  end
end

现在我可以将这些方法混合到需要它们的任何规范中。

答案 3 :(得分:4)

rspec 中,有一个配置不允许您删除未定义的方法。使用 rails 4 ,它甚至是标准行为:

# spec/spec_helper.rb
config.mock_with :rspec do |mocks|
  mocks.verify_partial_doubles = true
end

因此,投票率最高的答案与设计助手无关。将verify_partial_doubles更改为false或使用实际帮助程序。

答案 4 :(得分:1)

我想做@MikeFogg的解决方案-我在另一个视图规范中做了类似的事情来处理Pundit-但我当然遇到@ChrisEdwards指出的关于需要mocks.verify_partial_doubles = false的问题。

但是,我对在整个测试套件中将其关闭没有太大兴趣,这是一个很好的检查,“通常推荐”,并且在Rspec 4+中是默认设置。

我实际上首先在这里发布了一个解决方案,在此之前/之后的块中我重新配置了RSpec,但是我遇到了一种非常非常简单的方法来执行此操作,并且效果很好:

  before(:each) do
    without_partial_double_verification do
      allow(view).to receive(:resource).and_return(Student.new)
      allow(view).to receive(:resource_name).and_return(:student)
      allow(view).to receive(:devise_mapping).and_return(Devise.mappings[:student])
    end
    # other before_each configuration here as needed
  end

自2016年以来一直存在,最初名为without_verifying_partial_doubles,但已重命名为当前的without_partial_double_verification。在我能看到的任何地方似乎都没有记录在案。

答案 5 :(得分:0)

@sixty4bit answerthis answer here结合起来我提出了这个解决方案:

class DeviseHelpers < Module
  def initialize(resource_name, resource_class)
    @resource_name = resource_name
    @resource_class = resource_class
  end

  def extended(base)
    _resource_name = @resource_name
    _resource_class = @resource_class
    base.class_eval do
      define_method :resource_name do
        _resource_name
      end

      define_method :resource do
        @resource ||= _resource_class.new
      end

      define_method :devise_mapping do
        @devise_mapping ||= Devise.mappings[_resource_name]
      end
    end
  end

end

这允许您通过在规范的顶部要求它来使用不同的资源:

require 'support/devise_helpers'

然后像这样调用它:

before do
  view.extend(DeviseHelpers.new(:customer, Customer))
end

答案 6 :(得分:0)

对于RSpec 4,Rails 6和Devise 4.7,我对这里的其他建议不满意,或者对其他测试或生产代码的后果不满意。

allow(view).to receive(:current_user).and_return(user)
在我看来,

最终是对我有用的,而没有任何其他配置更改。 (必须先定义user。)

近年来,潜在的gem / framework发生了有意义的变化,使此处的其他一些解决方案无效的可能性不大。我更可能是错误配置了Devise,RSpec和/或相关的帮助程序。

我确认current_user已填充到rspec / rails / example / view_example_group.rb中,但在nil期间返回了render。我在view_example_group.rb中找到了此评论,并遵循了它:

        # The instance of `ActionView::Base` that is used to render the template.
        # Use this to stub methods _before_ calling `render`.
        #
        #     describe "widgets/new.html.erb" do
        #       it "shows all the widgets" do
        #         view.stub(:foo) { "foo" }
        #         render
        #         # ...
        #       end
        #     end
        def view
          _view
        end

https://github.com/rspec/rspec-rails/blob/main/lib/rspec/rails/example/view_example_group.rb

stub语法已被弃用,但view.stub(:current_user) { user }也将适用(暂时)。