我已经生成了运行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语句之前 - 但它仍然给我同样的错误,我不确定如何使用它。
我做错了什么?谢谢你的帮助。
答案 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 answer与this 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 }
也将适用(暂时)。