我正在编写一个简单的控制器测试,以确保我们在 GET 请求时获得 200 状态。我在网上遇到的每个答案都说要确保我们在
Devise
中包含正确的 spec_helper.rb
助手,但我尝试过的似乎都没有帮助。
错误:
NoMethodError:
undefined method `sign_in' for #<RSpec::ExampleGroups::ApplicationFunnelController::Index::WhenAccessed "returns 200" (./spec/requests/application_funnel_controller_spec.rb:7)>
控制器测试:
require 'spec_helper'
RSpec.describe ApplicationFunnelController, type: :request do
describe "index" do
context "when accessed" do
it "returns 200" do
user = FactoryBot.create(:user)
group = FactoryBot.create(:group, name: 'Testers')
user.groups << group
sign_in user
get become_a_member_path
expect(response.status).to eq 200
end
end
end
end
spec_helper.rb:
ENV["RAILS_ENV"] ||= "test"
require_relative "../config/environment"
require "rails/test_help"
require "database_cleaner"
require "rspec/rails"
require "capybara/rspec"
require "capybara/rails"
require "devise"
class ActiveSupport::TestCase
# Run tests in parallel with specified workers
parallelize(workers: :number_of_processors)
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
# Add more helper methods to be used by all tests here...
end
RSpec.configure do |config|
config.include Devise::Test::ControllerHelpers, type: :controller
config.include Devise::Test::ControllerHelpers, type: :view
config.include Devise::TestHelpers, type: :controller
config.include Devise::Test::ControllerHelpers, type: :routing
config.include Devise::TestHelpers, type: :routing
config.infer_spec_type_from_file_location!
DEFAULT_CLEANER_STRATEGY = :transaction
def with_truncation
DatabaseCleaner.strategy = :truncation
yield
ensure
DatabaseCleaner.strategy = DEFAULT_CLEANER_STRATEGY
end
config.include ActiveSupport::Testing::TimeHelpers
config.before :suite do
ActiveJob::Base.queue_adapter = :test
DatabaseCleaner.strategy = DEFAULT_CLEANER_STRATEGY
unless ENV["SEED"] == "false"
DatabaseCleaner.clean_with(:truncation, except: %w(ar_internal_metadata schema_migrations))
end
Rails.application.load_tasks
end
config.before { ActionMailer::Base.deliveries.clear }
end
经过几次搜索并阅读文档后,我认为找到了答案。
首先,据我所知,控制器规范中的
type: :request
不起作用。 控制器规格和请求规格之间存在差异。我建议您阅读提供的链接,以便您可以考虑要在代码库中包含哪种类型的测试。
现在,假设您想在控制器规范中登录用户工厂,您可以做的是创建一个
ControllerMacros
模块,并将其放入 spec/support
:
# =================================
# spec/support/controller_macros.rb
module ControllerMacros
def login_user(user)
@request.env["devise.mapping"] = Devise.mappings[:user]
sign_in user
end
end
# ====================
# spec/rails_helper.rb
require_relative 'support/controller_macros'
RSpec.configure do |config|
# For Devise > 4.1.1
config.include Devise::Test::ControllerHelpers, :type => :controller
# Use the following instead if you are on Devise <= 4.1.1
# config.include Devise::TestHelpers, :type => :controller
config.extend ControllerMacros, :type => :controller
end
# ======================================================
# spec/controllers/application_funnel_controller_spec.rb
RSpec.describe ApplicationFunnelController do
describe "index" do
context "when accessed" do
# You can optionally add this in you example.
before do
FactoryBot.create(:user).tap do |user|
group = FactoryBot.create(:group, name: 'Testers')
user.groups << group
login_user user
end
end
it "returns 200" do
get become_a_member_path
expect(response.status).to eq 200
end
end
end
end
以这种方式加载模块:
config.extend ControllerMacros, :type => :controller
应该允许您在控制器规格中使用
login_user
方法。
如果重复起来很烦人,您可以选择这样做:
module ControllerMacros
def login_user
before(:each) do
@request.env["devise.mapping"] = Devise.mappings[:user]
user = FactoryBot.create(:user)
sign_in user
end
end
end
只需调用控制器规范中的方法即可:
RSpec.describe ApplicationFunnelController do
login_user
# Tests here...
end
您可以在其存储库 wiki 中找到有关使用 Rspec 测试 Devise 的更多信息: