Railsアプリをテストしようとしています。今、小さなコントローラーをテストしていますが、問題があります。デバイスを使用して認証します。私がテストする私のコントローラーは、
class WidgetsController < ApplicationController
#skip_before_filter :authenticate, :only => [:new, :create]
before_filter :authenticate, :except=>[:disabled]
def index
@widgets = current_user.widgets.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: @widgets }
end
end
def new
@widget = Widget.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: @widget }
end
end
def create
@widget = Widget.new(params[:widget])
@widget.user_id = current_user.id
@widget.score = 0
@widget.total_score = 0
@widget.click_number = 0
@widget.average = 0
respond_to do |format|
if @widget.save
format.html { redirect_to edit_widget_path(@widget), notice: 'Widget was successfully created.' }
format.json { render json: @widget, status: :created, location: @widget }
else
format.html { render action: "new" }
format.json { render json: @widget.errors, status: :unprocessable_entity }
raise 'an error occurs when creation'
end
end
end
def show
@widget = Widget.find_by_uuid(params[:uuid])
respond_to do |format|
format.html # show.html.erb
format.json { render json: @widget }
end
end
def edit
@widget = Widget.find_by_uuid(params[:uuid])
end
def update
@widget = Widget.find_by_uuid(params[:uuid])
respond_to do |format|
if @widget.update_attributes(params[:widget])
format.html { redirect_to edit_widget_path(@widget), notice: 'Widget was successfully updated.' }
format.json { render json: @widget, status: :created, location: @widget }
else
format.html { render action: "edit" }
format.json { render json: @widget.errors, status: :unprocessable_entity }
raise 'there is an error when alteration'
end
end
end
def destroy
@widget = Widget.find_by_uuid(params[:uuid]).destroy
respond_to do |format|
format.html { redirect_to widgets_path }
format.json { head :no_content }
end
end
#generate widget
def generate
respond_to do |format|
format.js {}
end
rescue
#TODO add widget not found page
render :template => 'application/widget_not_found', :status => :not_found
end
protected
def authenticate
unless current_user
redirect_to root_url
end
end
end
私のルートファイルは、おそらくあなたがそれを調べたいと思うかもしれません。
Rwidget::Application.routes.draw do
match 'widgets' => 'widgets#index', :via => :get
match 'widgets/new' => 'widgets#new', :via => :get
match 'widgets' => 'widgets#create', :via => :post
match 'widgets/:uuid' => 'widgets#show', :via => :get
get 'widgets/:uuid/edit' => 'widgets#edit'
match 'widgets/:uuid' => 'widgets#update', :via => :put
match 'widgets/:uuid' => 'widgets#destroy', :via => :delete
resources :widgets, :collection => [:destroy]
match 'rws/generate/:uuid' => 'rws#generate'
get 'rws/:uuid' => 'rws#show'
put 'rws/:uuid' => 'rws#update'
post 'rws/getUserInfo' => 'rws#getUserInfo'
resources :authentications
match '/auth/:provider/callback' => 'authentications#create'
devise_for :users do
get '/users/sign_out' => 'devise/sessions#destroy'
end
root :to => "home#index"
そして私のcontroller_spec。rbは
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
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(:language => "en") }
post :create, :widget => {'these' => 'params'}
assigns(:widget) == @widgets
response.should redirect_to (edit_widget_path(@mock_widget))
end
end
describe "Get widget" do
it "shows exact widget via id" do
Widget.stub(:find).with("10") { [mock_widget] }
get :show
assigns(:mock_widget) == mock_widget
end
end
describe "Put widget" do
it "updates the widget attributes" do
Widget.stub(:find).with("6") { [mock_widget] }
mock_widget.should_receive(:update_attributes).with({'these' => 'params'})
put :update, :id => "6", :widget => {'these' => 'params'}
end
end
describe "delete destroy" do
it "destroys the requested widget" do
Widget.stub(:find).with("10") { [mock_widget] }
mock_widget.should_receive(:destroy)
get :destroy, :id => "10"
end
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
そして私の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'
# 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.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
最後に、サポートファイルの下にある私のdevise.rb、
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
end
それで。controller.specファイルをデバッグすると、describeブロックの更新と削除にcurrent_userがありません。私が走るとき私はender$ rspec spec/controllers/widgets_controller_spec.rb
直面します
Failures:
1) WidgetsController Put widget updates the widget attributes
Failure/Error: put :update, :id => "6", :widget => {'these' => 'params'}
NoMethodError:
undefined method `update_attributes' for nil:NilClass
# ./app/controllers/widgets_controller.rb:60:in `block in update'
# ./app/controllers/widgets_controller.rb:59:in `update'
# ./spec/controllers/widgets_controller_spec.rb:52:in `block (3 levels) in <top (required)>'
2) WidgetsController delete destroy destroys the requested widget
Failure/Error: get :destroy, :id => "10"
NoMethodError:
undefined method `destroy' for nil:NilClass
# ./app/controllers/widgets_controller.rb:72:in `destroy'
# ./spec/controllers/widgets_controller_spec.rb:60:in `block (3 levels) in <top (required)>'
Finished in 0.4569 seconds
6 examples, 2 failures
Failed examples:
rspec ./spec/controllers/widgets_controller_spec.rb:49 # WidgetsController Put widget updates the widget attributes
rspec ./spec/controllers/widgets_controller_spec.rb:57 # WidgetsController delete destroy destroys the requested widget
どうすれば修正できますか?
解決策: uuidを検索したため、findbyidをfindbyuuidにシフトしました。その後、配列を返す必要があり、この方法で取得しました。
Widget.stub(:find_by_uuid).with("6").and_return(mock_widget(:update_attributes => true))
終わった!