12

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

这就是我想出的:

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

对于它给我的渲染语句undefined local variable or method 'resource'谷歌搜索后,我发现我应该添加

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

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

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

4

7 回答 7

13

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

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
于 2013-11-12T14:18:48.133 回答
6

你知道吗?我在有人遇到类似问题的地方找到了这个答案。解决方案是在您的应用程序助手中包含以下代码:

def resource_name
  :user
end

def resource
  @resource ||= User.new
end

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

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

于 2013-01-20T18:20:23.827 回答
5

rspec中,有一个配置不允许您存根未定义的方法。对于rails 4,它甚至是标准行为:

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

因此,最高投票的答案不适用于设计助手。更改verify_partial_doublesfalse或使用实际的助手。

于 2015-07-23T18:16:09.903 回答
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

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

于 2015-07-04T17:22:14.153 回答
3

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

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

实际上,我首先在这里发布了一个解决方案,我在 before/after 块中重新配置了 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,但被重命名为 current without_partial_double_verification。在我能看到的任何地方似乎都没有记录。

于 2019-05-16T05:34:42.953 回答
0

在这里结合@sixty4bit 答案这个答案,我想出了这个解决方案:

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
于 2018-03-14T13:14:14.200 回答
0

对于 RSpec 4、Rails 6 和 Devise 4.7,我在这里的其他建议没有成功,或者担心对我的其他测试或生产代码的影响。

allow(view).to receive(:current_user).and_return(user)

在我看来,规范最终对我有用,而无需任何其他配置更改。(必须先定义user。)

近年来,底层 gems/框架发生了有意义的变化,这使得这里的一些其他解决方案无效,这并非不可能。更有可能是我错误配置了 Devise、RSpec 和/或相关帮助程序。

我确认current_user已在 rspec/rails/example/view_example_group.rb 中填充,但nilrender. 我在 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 }也可以使用(目前)。

于 2020-09-06T14:15:50.867 回答