我有一个 Rails 应用程序,我正在尝试对其进行测试。我使用 devise 登录。但是,当我想测试时,我遇到了一个问题:
Users/ender/Projects/ratingw/spec/controllers/widgets_controller_spec.rb:4:in `block in <top (required)>': undefined local variable or method `login_user' for #<Class:0x007fe909bd5070> (NameError)
首先,我想说我阅读了这个设计正式教程。
我的 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 'rspec/autorun'
require 'capybara/rspec'
# 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
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:twitter] = {
:provider => 'twitter',
:uid => '123545'
# etc.
}
OmniAuth.config.mock_auth[:twitter] = :invalid_credentials
config.include Devise::TestHelpers, :type => :controller
config.extend ControllerMacros, :type => :controller
config.include RequestMacros, :type => :request
# 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 = true
# 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
end
module ::RSpec::Core
class ExampleGroup
include Capybara::DSL
include Capybara::RSpecMatchers
end
end
而且我还有一个controller_macros.rb,它位于支持文件中:
module ControllerMacros
def login_user
before(:each) do
@request.env["devise.mapping"] = Devise.mappings[:user]
user = Factory(:user)
#user.confirm! # or set a confirmed_at inside the factory. Only necessary if you are using the confirmable module
sign_in user
end
end
end
最后,我的 controller_spec 文件是:
require 'spec_helper'
describe WidgetsController do
login_user
describe "User" do
before(:each) do
@current_user = mock_model(User, :id => 1)
@widget = mock_model(Widget, :user_id => 1)
Widget.stub!(:current_user).and_return(@current_user)
Widget.stub!(:widgets).and_return(@widget)
end
it "should have a current_user" do
subject.current_user.should_not be_nil
redirect_to widgets_path
end
it "should not have a current_user" do
redirect_to widgets_path new_user_session_path
end
end
def mock_widget(stubs={})
@mock_widget ||= mock_model(Widget, stubs).as_null_object
end
describe "Get index" do
it "should get all widgets " do
Widget.stub(:all) { [mock_widget] }
get :index
assigns(:widgets) == @widgets
end
end
describe "Post widget" do
it "creates a new widget" do
Widget.stub(:new).with({'these' => 'params'}) { mock_widget(:save => true) }
post :create, :widget => {'these' => 'params'}
assigns(:widget) == @widgets
response.should redirect_to (edit_widget_path(@mock_widget))
end
it "can not create a new widget" do
Widget.stub(:new).with({'these' => 'params'}) { mock_widget(:save => false) }
post :create, :widget => {'these' => 'params'}
assigns(:widget) == @widgets
redirect_to new_widget_path
end
end
describe "Get widget" do
it "shows exact widget via its uuid" do
Widget.stub(:find).with("10") { mock_widget(:save => true) }
get :show
assigns(:widget) == @widget
end
end
describe "Put widget" do
it "updates the widget attributes" do
Widget.stub(:find_by_uuid).with("6").and_return(mock_widget(:update_attributes => true))
mock_widget.should_receive(:update_attributes).with({'these' => 'params'})
put :update, :uuid => "6", :widget => {'these' => 'params'}
response.should redirect_to (edit_widget_path(@mock_widget))
end
it "can not update the widget attributes" do
Widget.stub(:find_by_uuid).with("6").and_return(mock_widget(:update_attributes => false))
mock_widget.should_receive(:update_attributes).with({'these' => 'params'})
put :update, :uuid => "6", :widget => {'these' => 'params'}
end
end
describe "delete destroy" do
it "destroys the requested widget" do
Widget.stub(:find_by_uuid).with("10").and_return(mock_widget)
mock_widget.should_receive(:destroy)
get :destroy, :uuid => "10"
end
end
end
我怎样才能解决这个问题?问题是什么?