Я новичок в разработке с Rails - я прочитал несколько книг и сейчас погружаюсь в голову.У меня есть базовое приложение, настроенное с моделью User, и UserSessions через Authlogic.Я тестирую с помощью RSpec.
Все мои тесты были пройдены ранее вчера (вроде, см. Ниже), затем реализованы функции сброса пароля (по электронной почте, HTTP), и теперь хороший кусок моих тестовсломался - похоже, что-то с входом в систему / Authlogic.
Я упомянул выше, что с самого начала у меня возникли проблемы с Authlogic в моих тестах ...Кажется, я не хочу входить в систему. В спецификации запросов (возможно, это лучше всего рассмотреть в отдельном вопросе), я не могу войти (через посещение полей login_path и fill_in), если я не зарегистрирую пользователя вручную (signup_path, fill_in и т. д.).в рамках этой спецификации.Фабрика, похоже, не работает ... Везде, где я смотрел, написано, что нужно делать @user = Factory.create (: user), а затем UserSession.create (@user), но для меня это обычно не получается.Иногда я могу использовать метод spec_helper (sign_in (@user)) для входа в систему, в других случаях происходит сбой.
Я должен отметить, что, несмотря на все мои тесты, все работает в режиме разработки.Чтение о TDD сначала сделало меня фанатичным на тестировании, но это подрывает мою мотивацию!
В любом случае ... вот некоторый соответствующий код.Пожалуйста, дайте мне знать, что еще требуется.
Типичные ошибки:
Failure/Error: response.should render_template('users/show')expecting <"users/show"> but rendering with <"users/new,>.....
6) UsersController GET index for non admin users should protect the page
Failure/Error: response.should redirect_to(root_path)
Expected response to be a redirect to <http://test.host/> but was a redirect to <http://test.host/user_sessions/new>
# ./spec/controllers/users_controller_spec.rb:72:in `block (4 levels) in <top (required)>'
11) UsersController POST 'create' success should redirect to the user show page
Failure/Error: response.should redirect_to(user_path(assigns(:user)))
Expected response to be a redirect to <http://test.host/users/5> but was a redirect to <http://test.host/>
# ./spec/controllers/users_controller_spec.rb:160:in `block (4 levels) in <top (required)>'
13) UsersController POST 'create' success should be logged in
Failure/Error: UserSession.find.should_not be_nil
expected: not nil
got: nil
Application Controller
class ApplicationController < ActionController::Base
protect_from_forgery
helper_method :logged_in?, :current_user, :admin?
force_ssl if Rails.env.production?
private
def logged_in? # allows use of be_logged_in in RSpec
!current_user.nil?
end
def admin? # For RSpec
current_user.admin?
end
def current_user_session
return @current_user_session if defined?(@current_user_session)
@current_user_session = UserSession.find
end
def current_user
return @current_user if defined?(@current_user)
@current_user = current_user_session && current_user_session.record
end
def require_user
unless current_user
store_location
flash[:error] = "You must be logged in to access this page"
redirect_to new_user_session_path
return false
end
end
def require_no_user
if current_user
store_location
flash[:error] = "You must be logged out to access this page"
redirect_to user_path(current_user.id)
return false
end
end
def require_admin
unless (current_user && current_user.admin?)
redirect_to root_path
end
end
def store_location
session[:return_to] = request.fullpath
end
def redirect_back_or_default(default)
redirect_to(session[:return_to] || default)
session[:return_to] = nil
end
end
UserSessions Controller
class UserSessionsController < ApplicationController
before_filter :require_no_user, :only => [:new, :create]
before_filter :require_user, :only => :destroy
def new
@user_session = UserSession.new
@title = "Log In"
end
def create
@user_session = UserSession.new(params[:user_session])
if @user_session.save
user = @user_session.user
flash[:success] = "Login successful!"
redirect_back_or_default user_path(user.id)
else
flash[:error] = "Incorrect user name or password"
redirect_to new_user_session_path
end
end
def destroy
current_user_session.destroy
flash[:notice] = "You have been logged out"
redirect_back_or_default(new_user_session_path)
end
end
UserКонтроллер:
class UsersController < ApplicationController
before_filter :require_no_user, :only => [:new, :create]
before_filter :require_user, :only => [:index, :show, :edit, :update, :destroy, :change_password]
before_filter :require_admin, :only => [:index, :destroy]
before_filter :check_for_last, :only => [:destroy]
def new
@title = "Sign Up"
@user = User.new
end
def index
@title = "User Index"
@users = User.find(:all)
end
def create
@user = User.new(params[:user])
if @user.save
flash[:notice] = "Thanks for signing up, we've delivered an email to you with instructions on how to complete your registration!"
@user.deliver_verification_instructions!
redirect_to root_url
#UserSession.create @user # Turned off Authlogic automatic session maintenance. See https://github.com/binarylogic/authlogic/issues/262
else
@title = "Sign Up"
render :new
end
end
def show
if current_user.admin?
@user = User.find(params[:id]) || current_user
else
@user = current_user
end
@title = "Profile for #{@user.name}"
end
def edit
if current_user.admin? && (params[:id] != current_user.id)
redirect_to user_path(current_user.id), :notice => "Although you are an admin, you tried to edit someone else's profile. Do this otherwise (console) to avoid errors"
end
@user = current_user
@title = "Edit User: #{@user.name}"
end
def update
@user = @current_user # makes our views "cleaner" and more consistent
if @user.update_attributes(params[:user])
flash[:success] = "Edited your profile!"
redirect_to user_path(@user)
else
render :edit
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User destroyed."
redirect_to users_path
end
def change_password
@user = current_user
@title = "Reset Password"
end
def update_password
@user = current_user
redirect_to root_path unless @user
@user.password = params[:user][:password]
@user.password_confirmation = params[:user][:password_confirmation]
if @user.save
UserSession.create @user # Turned off Authlogic automatic session maintenance. See https://github.com/binarylogic/authlogic/issues/262
flash[:success] = "Password successfully updated"
redirect_to user_path(@user.id)
else
render :action => :change_password
end
end
private
def check_for_last
if (User.all.size == 1)
flash[:notice] = "You are trying to delete the last user... do that in console"
redirect_to users_path
return false
end
end
end
Модель пользователя:
class User < ActiveRecord::Base
acts_as_authentic do |c|
c.logged_in_timeout(30.minutes)
c.login_field = :email
c.maintain_sessions = false
end
attr_accessible :name, :email, :password, :password_confirmation
validates :name, :length => (2..50)
validates :password, :length => {:minimum => 4}
def deliver_verification_instructions!
reset_perishable_token!
UserMailer.verification_instructions(self).deliver
end
def verify!
self.verified = true
self.save
end
def deliver_password_reset_instructions!
reset_perishable_token!
UserMailer.password_reset_instructions(self).deliver
end
end
Модель UserSession:
class UserSession < Authlogic::Session::Base
logout_on_timeout true
consecutive_failed_logins_limit 10
failed_login_ban_for 1.hour
validate :check_if_verified
private
def check_if_verified
errors.add(:base, "You have not yet verified your account") unless attempted_record && attempted_record.verified
end
end
Спецификация контроллера UserSession
require 'spec_helper'
describe UserSessionsController do
render_views
before(:each) do
@valid_user = Factory.create(:user)
activate_authlogic
end
describe "Authlogic & Application Controller tests" do
it "should allow login of a specified user, and logged_in? should provide correct response" do
sign_in(@valid_user)
UserSession.find.user.should == @valid_user
logged_in?.should be_true
logged_in?.email.should == @valid_user.email #logged_in function actually returns session
end
it "should allow logout of a specified user and logged_in? should provide correct response" do
sign_in(@valid_user)
logged_in?.should be_true
sign_out
logged_in?.should be_false
end
end # authlogic tests
describe "GET 'new'" do
it "should only get new if logged out" do
sign_in(@valid_user)
get :new
flash[:error].should =~ /You must be logged out/i
response.should redirect_to user_path(@valid_user.id)
response.code.should == "302" # redirected by require_no_user
end
end # get new
describe "POST 'create'" do
it "should create user session" do
logged_in?.should be_false
post :create, :user_session => { :email => @valid_user.email, :password => @valid_user.password }
logged_in?.should be_true
end
it "should redirect to user show page, with flash success" do
post :create, :user_session => { :email => @valid_user.email, :password => @valid_user.password }
assigns[:user_session].user.should == @valid_user
response.code.should == "302"
response.should redirect_to(user_path(@valid_user.id))
flash[:success].should =~ /login succ/i
end
it "should not create user session for invalid password" do
logged_in?.should be_false
post :create, :user_session => { :email => @valid_user.email, :password => "" }
logged_in?.should be_false
end
it "should redirect back to login page on invalid params, show proper flash" do
post :create, :user_session => { :email => @valid_user.email, :password => "" }
response.should redirect_to new_user_session_path
## BROKEN BECAUSE OF BEFORE_FILTER ##
# response.should render_template('new')
#response.should have_selector("div.flash.error", :content => "Incorrect user")
flash[:error].should =~ /Incorrect user name or password/i
end
it "should only create if logged out" do
sign_in(@valid_user)
post :create, :user_session => { :email => @valid_user.email, :password => @valid_user.password }
flash[:error].should =~ /You must be logged out/i
response.code.should == "302"
response.should redirect_to user_path(@valid_user.id)
end
end # post create
describe "DELETE destroy" do
it "should destroy user session if logged in" do
sign_in(@valid_user)
logged_in?.should be_true
delete :destroy
UserSession.find.should be_nil
response.should redirect_to new_user_session_path
end
it "should not destroy if logged out" do
logged_in?.should be_false
delete :destroy, :user_session => { :email => @valid_user.email, :password => @valid_user.password }
flash[:error].should =~ /You must be logged in/i
response.code.should == "302"
response.should redirect_to new_user_session_path
end
it "should redirect to login page and show correct flash on logout" do
sign_in(@valid_user)
logged_in?.should be_true
delete :destroy
flash[:notice].should =~ /You have been logged/i
response.should redirect_to new_user_session_path
end
end # delete destroy
end # specs
Спецификация контроллера пользователя
require 'spec_helper'
describe UsersController do
render_views
before(:each) do
activate_authlogic
end
describe "GET 'new'" do
it "should only work if not logged in" do
user = Factory.create(:user)
sign_in(user)
get :new
flash[:error].should =~ /must be logged out/i
response.should redirect_to user_path(user)
end
end
describe "GET index" do
before(:each) do
@admin_user = Factory.create(:user, :admin => true)
@signed_in_user = Factory.create(:user)
@user1 = Factory.create(:user)
@user2 = Factory.create(:user)
@user3 = Factory.create(:user)
@users = [@admin_user, @signed_in_user, @user1, @user2, @user3]
end
describe "for non signed in users" do
it "should deny access" do
get :index
flash[:error].should =~ /must be logged in/i
response.should redirect_to new_user_session_path
end
end
describe "for non admin users" do
it "should protect the page" do
sign_in(@signed_in_user)
get :index
response.should redirect_to(root_path)
flash[:error].should be_nil
flash[:success].should be_nil
flash[:notice].should be_nil
end
end
describe "for admin users" do
before(:each) do
sign_in(@admin_user)
end
end
end
describe "POST 'create'" do
describe "failure" do
before(:each) do
@attr = {:name=>"", :email=>"", :password=>"", :password_confirmation=>""}
end
it "should not create a user" do
lambda do
post :create, :user => @attr
end.should_not change(User, :count)
end
it "should render the 'new' page" do
post :create, :user => @attr
response.should render_template('new')
response.should have_selector("div.error_messages")
end
it "should only create a user if not logged in" do
@another_user = Factory.create(:user)
sign_in(@another_user)
@valid_attr = { :name=> 'New User', :email => 'somemail@gmail.com',:password => 'foobar', :password_confirmation => 'foobar' }
post :create, :user => @attr
flash[:error].should =~ /must be logged out/i
response.should redirect_to user_path(@another_user)
end
end #failure
describe "success" do
before(:each) do
@attr = { :name=> 'New User', :email => 'somemail@gmail.com',:password => 'foobar', :password_confirmation => 'foobar' }
end
it "should create a user" do
lambda do
post :create, :user => @attr
end.should change(User, :count).by(1)
end
it "should redirect to the user show page" do
post :create, :user => @attr
assigns[:user].email.should == "somemail@gmail.com"
response.should redirect_to(user_path(assigns(:user)))
end
it "should have a welcome message" do
post :create, :user => @attr
flash[:success].should =~ /signed/i
end
it "should be logged in" do
post :create, :user => @attr
UserSession.find.should_not be_nil
end
end #success
end # post create
describe "GET edit" do
before(:each) do
@valid_user = Factory.create(:user)
sign_in(@valid_user)
end
describe "success" do
it "should have the right title" do
get :edit, :id => @valid_user
response.should have_selector("title", :content => "Edit User: #{@valid_user.name}")
end
end # success
describe "failure" do
it "should not get edit if logged out" do
sign_out
get :edit, :id => @valid_user
flash[:error].should =~ /must be logged in/i
response.should redirect_to new_user_session_path
end
end # failure
end # GET edit
describe "GET show" do
before(:each) do
@valid_user = Factory.create(:user)
sign_in(@valid_user)
end
describe "success" do
it "should get show if logged in" do
get :show, :id => @valid_user
response.should be_success
end
end # success
describe "failure" do
it "should not get show if logged out" do
sign_out
get :show, :id => @valid_user
flash[:error].should =~ /must be logged in/i
response.should redirect_to new_user_session_path
end
it "should only be able to see their own page" do
@another_user = Factory.create(:user)
get :show, :id => @another_user
response.should have_selector("title", :content => "Profile for #{@valid_user.name}")
end
end # failure
describe "admin users" do
before(:each) do
@admin_user = Factory.create(:user, :admin => true)
sign_out
sign_in(@admin_user)
end
it "should get their own show page if that is the selection" do
get :show, :id => @admin_user
response.should have_selector("title", :content => "Profile for #{@admin_user.name}")
end
it "should also be able to get other people's show page if that is the selection" do
get :show, :id => @valid_user
response.should have_selector("title", :content => "Profile for #{@valid_user.name}")
end
it "should not show admin content on admin login" do
sign_in(@valid_user)
get :show, :id => @valid_user
response.should_not have_selector("section.admin>ul>li>a", :content => "Show Users", :href => users_path)
end
end
end # GET show
describe "PUT update" do
before(:each) do
@valid_user = Factory.create(:user)
sign_in(@valid_user)
end
describe "success" do
before(:each) do
@new_attrs = { :name => "new name", :email => "myname@gmail.com", :password => @valid_user.password, :password_confirmation => @valid_user.password}
end
it "should correctly update the user with valid attributes" do
put :update, :id => @valid_user.id, :user => @new_attrs
assigns[:user].name.should == "new name"
assigns[:user].email.should == "myname@gmail.com"
User.find(@valid_user.id).email.should == "myname@gmail.com"
end
it "should redirect to the user show page" do
put :update, :id => @valid_user.id, :user => @new_attrs
response.should redirect_to user_path(@valid_user)
flash[:success].should =~ /edited/i
end
end # success
describe "failure" do
before(:each) do
@bad_attrs = { :name => "", :email => "nottaken"}
end
it "should not update user attributes if invalid" do
original_email = @valid_user.email
put :update, :id => @valid_user, :user => @bad_attrs
@valid_user.reload
@valid_user.email.should == original_email
logged_in?.should be_true
User.find_by_email(original_email).should_not be_nil
end
it "should re-render the edit page" do
put :update, :id => @valid_user, :user => @bad_attrs
#controller.stub!(:require_user).and_return(true)
response.should render_template('edit')
logged_in?.should be_true
end
it "should not allow edit, even with valid attributes, if not logged in" do
sign_out
original_email = @valid_user.email
put :update, :id => @valid_user, :user => @new_attrs
@valid_user.reload
@valid_user.email.should == original_email
response.should redirect_to new_user_session_path
logged_in?.should be_false
end
it "should not allow you to take another user's email" do
@another_user = Factory.create(:user)
put :update, :id => @valid_user, :user => { :name => "valid name", :email => @another_user.email}
response.should render_template('edit')
response.should have_selector("div.error_messages")
end
end #failure
end # post update
describe "DELETE destroy" do
before(:each) do
@valid_user = Factory.create(:user)
end
describe "as a non-signed-in user" do
it "should deny access" do
delete :destroy, :id => @valid_user
flash[:error].should =~ /must be logged in/i
response.should redirect_to new_user_session_path
end
end
describe "as a non-admin user" do
it "should protect the page" do
sign_in(@valid_user)
delete :destroy, :id => @valid_user
response.should redirect_to(root_path)
flash[:error].should be_nil
flash[:success].should be_nil
flash[:notice].should be_nil
end
end
describe "as an admin user" do
before(:each) do
@admin = Factory(:user, :admin => true)
sign_in(@admin)
end
it "should destroy the user" do
lambda do
delete :destroy, :id => @valid_user
end.should change(User, :count).by(-1)
end
it "should redirect to the users page with the correct flash" do
delete :destroy, :id => @valid_user
response.should redirect_to(users_path)
flash[:success].should =~ /user destroyed/i
end
end
end
end
Фабрика пользователей:
Factory.define :valid_user , :class => User do |u|
u.name "brandon"
u.email "brandon@example.com"
u.password "foobar"
u.password_confirmation "foobar"
end
Factory.define :invalid_user , :class => User do |u|
u.name ""
u.email "brandon@example"
u.password "f"
u.password_confirmation "f"
end
Factory.sequence :email do |n|
"person#{n}@example.com"
end
Factory.sequence :name do |n|
"John Doe the #{n}"
end
Factory.define :user do |f|
f.name {Factory.next(:name)}
f.email {Factory.next(:email)}
f.password "foobar"
f.password_confirmation "foobar"
end
Spec helper
require 'database_cleaner'
require 'spork'
require 'factory_girl'
require 'authlogic/test_case'
Spork.prefork do
# Loading more in this block will cause your tests to run faster. However,
# if you change any configuration or code from libraries loaded here, you'll
# need to restart spork for it take effect.
def sign_in(user)
u = UserSession.create(user)
end
def sign_out
us = UserSession.find
us.destroy
end
def logged_in?
current_user_session = UserSession.find
return current_user_session.record if current_user_session
return false
end
DatabaseCleaner.strategy = :truncation
# 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 'webrat'
include Authlogic::TestCase
# 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}
Webrat.configure do |config|
config.mode = :rails
end
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
ApplicationController.skip_before_filter :activate_authlogic
config.before(:each, :type => :request) do
activate_authlogic
#UserSession.create(User.find_by_email!(email))
end
# 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
end
Spork.each_run do
# This code will be run each time you run your specs.
FactoryGirl.reload
ActiveSupport::Dependencies.clear
RSpec.configure do |config|
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
# DatabaseCleaner.clean
end
В стороне (в некоторой степени, может быть связано с другими моими проблемами), я продолжаю получать эторасстраивающая ошибка
16) UsersController GET edit success should render the 'edit' page
Failure/Error: response.should render_template('edit')
expecting <"edit"> but rendering with <"">
# ./spec/controllers/users_controller_spec.rb:203:in `block (4 levels) in <top (required)>'
Я ценю любую помощь, которая может быть оказана - я в своем уме !!Я выложу любой дополнительный код, который вам нужен.СПАСИБО!