我的控制器测试没有通过。我在我的ReviewsController中有一个before_acton来测试当前用户。如果没有,则不应该完成创建操作和重定向。但它确实创建了它,尽管会话[:user_id]为零。这是我的代码:
it "doesnt create review if there is valid input, but not authenticated" do
video = Video.create(title: "new title", description: "new description")
review = Review.create(content: "content1", rating: 1)
expect(Review.count).to eq(0)
end
在我的ReviewsController中:
def create
@video = Video.find(params[:video_id])
@review = Review.new(parameters)
rating = params[:review][:rating]
content = params[:review][:content]
@review.content = content
@review.rating = rating
@review.user_id = current_user.id
@review.video = @video
@review.save
redirect_to @video
end
我在评论控制器中有一个before_action,用于测试用户是否经过身份验证。如果会话[:user_id]为nil,则会重定向到sign_in_path。以下是方法:
def current_user
@current_user = User.find(session[:user_id]) if session[:user_id]
end
def require_user
redirect_to sign_in_path unless current_user
end
在我的reviews_controller_spec.rb文件中,它不应该创建评论,因为它不应该超过before_action:require_user
为什么仍在创建审核对象?为什么没有before_action过滤器阻止它?测试失败,只是说它希望Review.count为0,但得到1。
答案 0 :(得分:1)
# config/routes.rb
resources :videos, shallow: true do
resources :reviews
end
没有必要将参数绑定到属性1-1。实际上这样做会让你的控制器过于冗长,加上它的无聊就像输入它一样。
class ReviewsController < ApplicationController
before_filter :authenticate_user!
def create
@video = Video.find(params[:video_id])
@review = current_user.reviews.new(review_params) do |r|
r.video = @video
end
end
private
# this is mass assignment protection
def review_params
params.require(:review).permit(:rating, :content)
end
end
如果您决定推出自己的身份验证(这是一个坏主意),请不要在控制器和视图中重复此操作:
module AuthenticationHelper
def current_user
@current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def sign_in(user)
@current_user = user
session[:user_id] = user.id
end
def sign_out
@current_user = nil
reset_session
end
def authenticate_user!
raise User::NotAuthorized unless current_user
end
end
一个关键点是选择退出安全模型要好得多,因为它消除了遗漏路线的风险:
class ApplicationController
include AuthenticationHelper
rescue_from User::NotAuthorized, with: :deny_access!
# use skip_before_action :authenticate_user! if
# you don't want a route / controller to require auth.
before_action :authenticate_user!
private
def deny_access!
redirect_to root_path
end
end
因此,为了测试ReviewsController,我们会这样做:
describe ReviewsController do
let(:user) { User.create(name: 'joe') }
let(:video) { Video.create(name: 'Cats Gone Wild') }
describe "#create" do
let(:valid_attributes) { { video_id: video, title: "new title", description: "new description" } }
context "when unauthorized" do
it "does not create a review" do
expect { post :create, valid_attributes }.to_not change(Review, :count)
end
end
context "when authorized" do
before { subject.stub(:current_user) { user } }
# ...
end
end
end
要点:
let
设置测试依赖项expect { action }.to change
来测试操作是否会改变数据库。对.count == 0
进行测试可能会导致误报。