控制器测试未通过导轨

时间:2016-02-04 07:05:11

标签: ruby-on-rails ruby

我的控制器测试没有通过。我在我的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。

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进行测试可能会导致误报。