问题描述
我的控制器规格在我一个接一个运行时通过,但当我将它们作为控制器一起运行时都失败了.
My controller specs are passing when I run them one by one but are all failing when I run them together as controllers.
$rspec spec/controllers
22) SubjectsController GET index assigns all subjects as @subjects
Failure/Error: get :index, {}
ActionController::RoutingError:
No route matches {:controller=>"subjects"}
# ./spec/controllers/subjects_controller_spec.rb:13:in `block (3 levels) in <top (required)>'
我的猜测是它一定与数据库清理有关,但我不确定在控制器规范中排除路由错误的最佳方法.
My guess is it must be something to do with database cleaner but I'm not sure best way to troubleshoot routing errors in controller specs.
宝石文件
gem 'rails', '3.2.13'
gem 'mysql2', '0.3.13'
gem 'devise', '2.2.3'
...
...
group :development, :test do
gem 'rspec-rails', '~> 2.99'
gem 'webrick', '~> 1.3'
gem 'rails-erd', '~> 1.1'
gem 'bullet', '~> 4.6'
gem 'pry-rails', '~> 0.3'
gem 'factory_girl_rails', '~> 4.4'
gem 'faker', '~> 1.2'
end
group :test do
gem 'cucumber-rails', :require => false
gem 'capybara', '~> 2.2.1'
gem 'database_cleaner', '~> 1.3.0'
gem 'launchy', '~> 2.4.2'
gem 'shoulda-matchers', '~> 2.6.1'
gem 'vcr', '~> 2.9.2'
gem 'webmock', '~> 1.13.0'
gem 'zeus', '~> 0.13.3'
end
spec/spec_helper.rb
spec/spec_helper.rb
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] = 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rake'
require 'sidekiq/testing'
Sidekiq::Logging.logger = nil
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
RSpec.configure do |config|
# ## Mock Framework
#
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
#
# config.mock_with :mocha
# config.mock_with :flexmock
# config.mock_with :rr
config.mock_with :rspec
# Only run tests that have this filter, if it exists
# config.filter_run :debug => true
# Run all the tests when all the tests are filtered
# config.run_all_when_everything_filtered = true
config.treat_symbols_as_metadata_keys_with_true_values = true
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
# config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = false
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = false
config.include FactoryGirl::Syntax::Methods
config.include Devise::TestHelpers, :type => :controller
config.extend ControllerMacros, :type => :controller
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:facebook] = OmniAuth::AuthHash.new( {
provider: 'facebook',
uid: '123545',
info: {
first_name: 'John',
last_name: 'Doe',
email: '[email protected]'
},
credentials: {
token: "123456",
expires_at: Time.now + 1.week
},
extra: {
raw_info: {
gender: 'male'
}
}
})
# silence rspec 3 deprecation warnings
config.expose_current_running_example_as :example
config.infer_spec_type_from_file_location!
def login(user)
@request.env["devise.mapping"] = Devise.mappings[:user]
@user = user
@user.confirm! # or set a confirmed_at inside the factory. Only necessary if you are using the confirmable module
allow(controller).to receive(:current_user).and_return(@user)
sign_in @user
end
def logged_user
@user
end
end
spec/support/database_cleaner.rb
spec/support/database_cleaner.rb
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
load "#{Rails.root}/db/seeds.rb"
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, :js => true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
spec/controllers/subjects_controller_spec.rb
spec/controllers/subjects_controller_spec.rb
require 'spec_helper'
describe SubjectsController, :type => :controller do
before(:each) do
login create(:admin)
end
describe "GET index" do
it "assigns all subjects as @subjects" do
subject = create(:subject)
get :index, {}
expect(assigns(:subjects)).to include(subject)
end
end
describe "GET show" do
it "assigns the requested subject as @subject" do
subject = create(:subject)
get :show, {:id => subject.to_param}
expect(assigns(:subject)).to eq(subject)
end
end
describe "GET new" do
it "assigns a new subject as @subject" do
get :new, {}
expect(assigns(:subject)).to be_a_new(Subject)
end
end
describe "GET edit" do
it "assigns the requested subject as @subject" do
subject = create(:subject)
get :edit, {:id => subject.to_param}
expect(assigns(:subject)).to eq(subject)
end
end
describe "POST create" do
describe "with valid params" do
it "creates a new Subject" do
expect {
post :create, {:subject => attributes_for(:subject) }
}.to change(Subject, :count).by(1)
end
it "assigns a newly created subject as @subject" do
post :create, { :subject => attributes_for(:subject) }
expect(assigns(:subject)).to be_a(Subject)
expect(assigns(:subject)).to be_persisted
end
it "redirects to the created subject" do
post :create, {:subject => attributes_for(:subject) }
expect(response).to redirect_to(subjects_path)
end
end
describe "with invalid params" do
it "assigns a newly created but unsaved subject as @subject" do
allow_any_instance_of(Subject).to receive(:save).and_return(false)
post :create, {:subject => {}}
expect(assigns(:subject)).to be_a_new(Subject)
end
it "re-renders the 'new' template" do
allow_any_instance_of(Subject).to receive(:save).and_return(false)
post :create, { :subject => {} }
expect(response).to render_template("new")
end
end
end
describe "PUT update" do
describe "with valid params" do
it "updates the requested subject" do
@subject = create(:subject, name: "Alice")
put :update, id: @subject, subject: attributes_for(:subject, name: "Bob")
@subject.reload
@subject.name.should eq("Bob")
end
it "assigns the requested subject as @subject" do
@subject = create(:subject)
put :update, {:id => @subject, :subject => attributes_for(:subject) }
expect(assigns(:subject)).to eq(@subject)
end
it "redirects to the subject" do
@subject = create(:subject)
put :update, {:id => @subject, :subject => attributes_for(:subject) }
expect(response).to redirect_to(edit_subject_path)
end
end
describe "with invalid params" do
it "assigns the subject as @subject" do
@subject = create(:subject)
allow_any_instance_of(Subject).to receive(:save).and_return(false)
put :update, {:id => @subject, :subject => {}}
expect(assigns(:subject)).to eq(@subject)
end
it "re-renders the 'edit' template" do
@subject = create(:subject)
allow_any_instance_of(Subject).to receive(:save).and_return(false)
put :update, {:id => @subject, :subject => {}}
expect(response).to render_template("edit")
end
end
end
describe "DELETE destroy" do
it "destroys the requested subject" do
subject = create(:subject)
expect {
delete :destroy, {:id => subject.id}
}.to change(Subject, :count).by(-1)
end
it "redirects to the subjects list" do
subject = create(:subject)
delete :destroy, {:id => subject.id }
expect(response).to redirect_to(subjects_url)
end
end
end
耙路线
suggested_subjects GET /suggested_subjects(.:format) suggested_subjects#index
make_preferred_subject PUT /subjects/:id/make_preferred(.:format) subjects#make_preferred
subjects GET /subjects(.:format) subjects#index
POST /subjects(.:format) subjects#create
new_subject GET /subjects/new(.:format) subjects#new
edit_subject GET /subjects/:id/edit(.:format) subjects#edit
subject GET /subjects/:id(.:format) subjects#show
PUT /subjects/:id(.:format) subjects#update
app/controllers/subjects_controller.rb
app/controllers/subjects_controller.rb
class SubjectsController < ApplicationController
load_and_authorize_resource
def index
@subjects = Subject.filter(params)
respond_to do |format|
format.html
format.json { render json: {total: @subjects.count, subjects: @subjects}.to_json }
end
end
....
....
end
推荐答案
想通了.
ActionController::RoutingError 是另一个控制器规范调用的结果:
The ActionController::RoutingError was a result of another controller spec which was calling:
routes.draw
此调用消除了后续规范的路由.目前的解决方案(感谢:
This call wiped out the routes for subsequent specs. The solution for now (thanks to:
http://pivotallabs.com/adding-routes-for-tests-specs-with-rails-3/ ) 添加:
after do
# be sure to reload routes after the tests run, otherwise all your
# other controller specs will fail
Rails.application.reload_routes!
end
也有帮助:
https://github.com/rspec/rspec-rails/issues/817
https://github.com/rspec/rspec-rails/issues/636
希望这会有所帮助并祝您好运!
Hope this helps and good luck!
这篇关于Rails 控制器 rspecs 因规范/控制器的 RoutingError 失败,但通过个别测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!